张孝祥_Java多线程与并发库高级应用02

03. 传统线程互斥技术

       线程安全问题例子:银行转账

       同一个账户一边进行出账操作(自己交学费),另一边进行入账操作(别人给自己付款),线程不同步带来的安全问题

示例:逐个字符的方式打印字符串

class Outputer

{

       public void output(String name)

       {

       int len =name.length();

       for (int i=0; i<len; i++)

              SOP(name.charAt(i));逐个字符打印

       SOP();换行

}

}

public void test()

{

       Outputeroutputer = new Outputer();

       newThread(

new Runnable()

{

       public void run()

       {

              Thread.sleep(100);

       outputer.output(“zhangxiaoxiang”);

}

}).start();

       newThread(

new Runnable()

{

       public void run()

       {

              Thread.sleep(100);

       outputer.output(“lihuoming”);

}

}).start();

}

注意:

内部类不能访问局部变量,要访问需加final

静态方法中不能创建内部类的实例对象

打印结果发现的问题:线程不同步所致,两个线程都在使用同一个对象

要避免下边产生的问题,左边方法体中的代码要实现原子性

有一个线程正在使用这个方法的代码,别的线程就不能再使用。

就和厕所里的坑一样,已经有人在用了,别人就不能再去用了。

Java中某段代码要实现排他性,就将这段代码用synchronized关键字保护起来。

同步锁可以用任意对象,相当于门锁

synchronizedname

{

for (int i=0; i<len; i++)

       SOP(name.charAt(i));逐个字符打印

       SOP();换行

}

这样的话,有一个线程进入保护区域后,没出来的话,别的线程就不能进入保护区域。


互斥方法:

       a、同步代码块

              synchronized(lock){}

       b、同步方法

              方法返回值前加synchronized

              同步方法上边用的锁就是this对象

              静态同步方法使用的锁是该方法所在的class文件对象

使用synchronized关键字实现互斥,要保证同步的地方使用的是同一个锁对象

       public synchronized void output(String name)

       {

       int len =name.length();

       这里就不要再加同步了,加上极易出现死锁

       for (int i=0; i<len; i++)

              SOP(name.charAt(i));逐个字符打印

       SOP();换行

}

 

04. 传统线程同步通信技术

       面试题,子线程10次与主线程100次来回循环执行50次

       下面是我刚看完面试题就暂停视频自己试着写的代码,还可以,结果完成要求了

在单次循环结束后让这个刚结束循环的线程休眠,保证另一个线程可以抢到执行权。

public class ThreadInterViewTest

{

       /**

        * 刚看到面试题没看答案之前试写

        * 子线程循环10次,回主线程循环100次,

        * 再到子线程循环10次,再回主线程循环100次

        * 如此循环50次     

        */

       publicstatic void main(String[] args)

       {

              intnum = 0;

              while(num++<50)

              {

                     newThread(new Runnable()

                                   {

                                          @Override

                                          public void run()

                                          {

                                                 circle("子线程运行", 10);

                                          }

                                   }).start();

                     try

                     {

                            //加这句是保证上边的子线程先运行,刚开始没加,主线程就先开了

                            Thread.sleep(2000);

                     }catch (InterruptedException e)

                     {

                            e.printStackTrace();

                     }

                     circle("主线程", 100);  

              }

       }

      

       publicstatic synchronized void circle(String name, int count)

       {

              for(int i=1; i<=count; i++)

              {

                     System.out.println(name+"::"+i);

              }

              try

              {

                     Thread.sleep(5000);

              }catch (InterruptedException e)

              {

                     e.printStackTrace();

              }

       }

}

 

张老师讲的方法:

1、将子线程和主线程中要同步的方法进行封装,加上同步关键字实现同步

2、两个线程间隔运行,添加一个标记变量进行比较以实现相互通信,加色的部分

wait   notify  notifyAll  wait会抛出异常

class Business

{

       private boolean bShouleSub = true;

       publicsynchronized void sub()

       {

              if (bShouleSub)

              {

                     for (int i=1; i<11; i++)

                     SOP(sub+i);

              bShouldSub= false;

              this.notify();

}

else

       this.wait();

}

       publicsynchronized void main()

       {

              if (!bShouldSub)

              {

                     for (int i=1; i<101; i++)

                     SOP(main+i);

              bShouldSub= true;

              this.notify();

}

else

       this.wait();

}

}

经验:要用到共同数据(包括同步锁)或相同算法的多个方法要封装在一个类中

       锁是上在代表要操作的资源类的内部方法中的,而不是上在线程代码中的。这样写出来的类就是天然同步的,只要使用的是同一个new出来的对象,那么这个对象就具有同步互斥特性

       判断唤醒等待标记时使用while增加程序健壮性,防止伪唤醒

此处使用while以增加程序健壮性,因为存在虚假唤醒,有时候并没有被notify就醒了。如果该方法没有同步的话,此处就更要使用while进行判断了,避免进程不同步问题


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值