JavaSE-多线程-第二讲
多线程-2
静态同步函数
面试问:静态同步函数锁是哪一个?
静态方法中根本无this ,此时同步代码块中使用 sychronized(this) 与 public static void show() 使用的锁是不一样的。静态同步函数使用的同步锁是当前类的字节码对象。类进栈的时候,java 类进内存会创建字节码对象(当前class 文件所属对象).
获取字节码对象的方法:
/*** 或取类字节码对象的两种方法:
-
class getClass class thread.Ticket
-
Class clazz class thread.Ticket
*/
System.out.println(" class getClass "+ticket.getClass());
Class clazz= Ticket.class;
System.out.println(" Class clazz "+clazz);
package thread;
class Ticket implements Runnable{
private static int num =100;
boolean flag=true;
// Object object =new Object();
@Override
public void run() {
if(flag==true){
while (true){
synchronized (this.getClass()){//当前类的字节码对象
if(num>0){
try{
Thread.sleep(100);
}catch (InterruptedException e){
e.printStackTrace();
}
System.out.println(" thread name"+Thread.currentThread() +"obj ="+num--);
}
}
}
}else{
while (true){
this.show();
}
}
}
//封装函数
public static synchronized int show(){
if(num>0){
try{
Thread.sleep(10);
}catch (InterruptedException e){
e.printStackTrace();
}
System.out.println(" thread name"+Thread.currentThread() +"num ="+num--);
}
if(num==0){
return 1;
}
return 0;
}
}
public class SynFunctionLockDemo {
public static void main(String[] args) {
Ticket ticket =new Ticket();
/*** 或取类字节码对象的两种方法:
* class getClass class thread.Ticket
* Class clazz class thread.Ticket
*/
System.out.println(" class getClass "+ticket.getClass());
Class clazz= Ticket.class;
System.out.println(" Class clazz "+clazz);
Thread thread1 =new Thread(ticket);
Thread thread2 =new Thread(ticket);
/* thread1.start();
try{
Thread.sleep(100);
}catch (InterruptedException e){
e.printStackTrace();
}
ticket.flag=false;
thread2.start();*/
}
}
单例模式涉及的多线程问题
// 饿汉式—延迟加载模式 (技术细节,面试时候都面这一个!)
// 1. 有共享数据 sinlge 对象
// 2. 有多条语句操作共享数据? getsIngton()有 多条语句
//解决方法:1.同步函数 加同步但是每次都要synchronized 判断锁 执行效率降低。
//同步代码块:
// 此时多加一层 if(single== null )
class Sinlge {
private static Sinlge sinlge;
private SIngton(){
}
/* 方法 1; 同步函数 但是效率低
public static synchronized Sinlge getsIngton(){ //多条语句有安全隐患
if(sinlge==null){
// 执行过程中 线程0 线程1都会进入这里 可能都 new 对象
sinlge =new Sinlge();
}
return sinlge;
}*/
// 同步代码块 1.加第一层判断是为了提高效率
线程0 获得锁,此时 single 还是null 线程1再进入判断 sychronized
public static Sinlge getsIngton(){ //多条语句有安全隐患
**if(sinlge==null){**
synchronized (Sinlge.class){
// 线程0 线程1 可能都 new 对象
**if(sinlge==null){**
sinlge =new Sinlge();
}
}
}
return sinlge;
}
}
//懒汉式-- 不存在安全问题
// 1. 有共享数据 sinlge 对象
// 2. 有多条语句操作共享数据? getsIngton()只有一条语句
class Single2 {
private static final Single2 single =new Single2();
private Single2(){
}
public static Single2 getInstance(){
return single;
}
}
多线程死锁
面试请写出一个死锁程序?
原则:死锁:常见情景之一:同步的嵌套。
package thread;
class TicketDemo implements Runnable{
private boolean flag;
private int num=100;
TicketDemo (boolean flag){
this.flag=flag;
}
@Override
public void run() {
if(flag){
synchronized (MyLock.myLock1){
System.out.println(" lock a"+Thread.currentThread().getName());
synchronized (MyLock.myLock2){
System.out.println(" flag= true"+Thread.currentThread()+" num"+num--);
}
}
}else {
synchronized (MyLock.myLock2){
System.out.println(" lock b"+Thread.currentThread().getName());
synchronized (MyLock.myLock1){
System.out.println(" flag= flase"+Thread.currentThread()+" num"+num--);
}
}
}
}
}
class MyLock{
public static MyLock myLock1= new MyLock();
public static MyLock myLock2 =new MyLock();
}
public class DeathLock {
public static void main(String[] args) {
TicketDemo ticketDemo =new TicketDemo(true);
TicketDemo ticketDemo1 =new TicketDemo(false);
Thread thread =new Thread(ticketDemo);
Thread thread1 =new Thread(ticketDemo1);
thread.start();
thread1.start();
}
}
输出 lock aThread-0
lock bThread-1:
此时 线程0获得 locka 但是没有获得lockb 线程 1 获得lockb 没有获得 locka
什么时候需要多线程通讯?
1.多个线程共享资源。2.对共享资源的处理不同。
package thread;
class Resoure2{//资源
public String name;
public String sex;
}
//输入
class InPut2 implements Runnable{
Resoure2 r;
InPut2( Resoure2 r){
this.r=r;
}
@Override
public void run() {
int x=0;
while (true){
synchronized (r){
if(x==0){
r.name="wwwww";
r.sex=" man ";
}else {
r.name="qqq";
r.sex="women";
System.out.println(" 中文 women ----------------------------");
}
}
x=(x+1)%2; // 1 0 1 0
System.out.println("22222222222222 x=" +x);
}
}
}
//输出
class OutPut2 implements Runnable{
Resoure2 r;
OutPut2(Resoure2 r){
this.r=r;
}
@Override
public void run() {
while (true){
synchronized (r){
try{
Thread.sleep(1000);
}catch ( InterruptedException e){
e.printStackTrace();
}
System.out.println(" out name "+r.name+ "sex"+r.sex);
}
}
}
}
public class ResoureDemo {
public static void main(String[] args) {
Resoure2 r= new Resoure2();
InPut2 inPut =new InPut2(r);
OutPut2 outPut =new OutPut2(r);
Thread thread1= new Thread(inPut);
Thread thread2= new Thread(outPut);
thread1.start();
thread2.start();
}
}
什么是等待唤醒机制?
使用到的方法:
1,wait(): 让线程处于冻结状态,被wait的线程会被存储到线程池中。
2,notify():唤醒线程池中一个线程(任意).
3,notifyAll():唤醒线程池中的所有线程。
这些方法都必须定义在同步中 也就是sychronized{ }内。
因为这些方法是用于操作线程状态的方法。
必须要明确到底操作的是哪个锁上的线程。例如:下例中 r.wait() r.notify() 直接调用会出现:java.lang.IllegalMonitorStateException
问题:为什么操作线程的方法wait notify notifyAll定义在了Object类中?
因为这些方法是监视器的方法。监视器其实就是锁 例如: Resource r。
锁可以是任意的对象,任意的对象调用的方式一定定义在Object类中。
唤醒机制原理解释:
1.input 获得锁 设置name =mike sex =nan
表示赋值成功,input 还有执行权,又会赋值此时name="丽丽"可能会赋值多次,无限循环。 flag=true 表示已经赋值,应该output 输出但是执行权还在input,这个时候flag=true要让 input 停一下. 加入判断:
if(flag){
r.wait();
}
等到output 执行完在唤醒。
如果 output 获得执行权:flag==flase 也要处于冻结状态。
//资源
class Resource
{
private String name;
private String sex;
public boolean flag= false;
}
//输入
class Input implements Runnable
{
Resource r ;
// Object obj = new Object();
Input(Resource r)
{
this.r = r;
}
public void run()
{
int x = 0;
while(true)
{
System.out.println(" input 1");
synchronized(r)
{
if(r.flag){
System.out.println(" input --wait");
try{ r.wait();}catch ( InterruptedException e){ e.printStackTrace();}
}
System.out.println(" input2-- synchronized-beign");
if(x==0)
{
r.name = "小王";
r.sex = "男";
}
else
{
r.name = "丽丽";
r.sex = "女";
}
System.out.println(" input2-- synchronized-end");
r.notify();
r.flag=true;
}
x = (x+1)%2;
System.out.println(" input退出锁 x="+x);
}
}
}
//输出
class Output implements Runnable
{
Resource r;
// Object obj = new Object();
Output(Resource r)
{
this.r = r;
}
public void run()
{
while(true)
{
System.out.println(" output1");
synchronized(r)
{
if(!r.flag){
System.out.println(" out --wait");
try{ r.wait();}catch ( InterruptedException e){ e.printStackTrace();}
}
System.out.println(" output2- synchronized-begin");
System.out.println(" output2");
System.out.println(r.name+"....."+r.sex);
System.out.println(" output2- synchronized-end");
r.notify();
r.flag=false;
}
System.out.println(" output退出锁");
}
}
}
public class ResourceDemo {
public static void main(String[] args)
{
System.out.println(" bengin ----");
//创建资源。
Resource r = new Resource();
//创建任务。
Input in = new Input(r);
Output out = new Output(r);
//创建线程,执行路径。
Thread t1 = new Thread(in);
Thread t2 = new Thread(out);
//开启线程
t1.start();
t2.start();
}
执行结果:
bengin ----
input 1
input2-- synchronized-beign
output1
input2-- synchronized-end
output2- synchronized-begin
output2
input退出锁 x=1
input 1
小王…男
output2- synchronized-end
output退出锁
output1
out --wait
input2-- synchronized-beign
input2-- synchronized-end
output2- synchronized-begin
output2
input退出锁 x=0
input 1
丽丽…女
output2- synchronized-end
output退出锁
output1
input2-- synchronized-beign
input2-- synchronized-end
output2- synchronized-begin
output2
小王…男
output2- synchronized-end
input退出锁 x=1
input 1
input2-- synchronized-beign
input2-- synchronized-end
output退出锁
output1
output2- synchronized-begin
output2
丽丽…女
output2- synchronized-end
output退出锁
output1
out --wait
input退出锁 x=0
input 1
input2-- synchronized-beign
input2-- synchronized-end
output2- synchronized-begin
output2
input退出锁 x=1
input 1
小王…男
output2- synchronized-end
output退出锁
output1
input2-- synchronized-beign
input2-- synchronized-end
output2- synchronized-begin
output2
丽丽…女
output2- synchronized-end
output退出锁
output1
out --wait
多线程唤醒机制优化
使用同步函数代替同步代码块做封装
name 和sex 设置成私有, 同步函数 set ,out ;
//代码优化 ----等待唤醒机制
//资源
class Resource3
{
private String name;
private String sex;
public boolean flag= false;
//使用同步函数
public synchronized void set( String name,String sex){
if(flag){
try{
this.wait();
}catch (InterruptedException e){
e.printStackTrace();
}
}
this.name =name;
this.sex=sex;
this.flag=true;//表示有值了
this.notify();//唤醒 out
}
public synchronized void out(){
if(!flag){
try{
this.wait();
}catch (InterruptedException e){
e.printStackTrace();
}
}
System.out.println(" name "+this.name+" sex "+this.sex);
this.flag=false;
this.notify();
}
}
//输入
class Input3 implements Runnable
{
Resource3 r ;
// Object obj = new Object();
Input3(Resource3 r)
{
this.r = r;
}
public void run()
{
int x = 0;
while(true)
{
if(x==0)
{
r.set("小王","男");
}
else
{
r.set("丽丽","女");
}
// System.out.println(" input2-- synchronized-end");
x = (x+1)%2;
}
}
}
//输出
class Output3 implements Runnable
{
Resource3 r;
// Object obj = new Object();
Output3(Resource3 r)
{
this.r = r;
}
public void run()
{
while(true)
{
// System.out.println(" output1");
r.out();
}
}
}
public class ResourceDemo3 {
public static void main(String[] args)
{
System.out.println(" bengin ----");
//创建资源。
Resource3 r = new Resource3();
//创建任务。
Input3 in = new Input3(r);
Output3 out = new Output3(r);
//创建线程,执行路径。
Thread t1 = new Thread(in);
Thread t2 = new Thread(out);
//开启线程
t1.start();
t2.start();
}
}