黑马程序员——线程的总结(二)
2015-01-20 21:43
274 查看
------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
线程的总结(二)
死锁:
同步中嵌套同步,而锁却不同!
实际团体协作开发,各个模块交叉调用(持有了一个锁后调用其他模块的方法,而其他模块的方法又需要持有锁),相互等待就有可能会出现死锁,因为本来模块相互调用一般不关心具体实现,只依赖于接口
解决方式:
1)尽量使用tryLock(long timeout, TimeUnit unit)的方法(ReentrantLock、ReentrantReadWriteLock),设置超时时间,超时可以退出防止死锁。
2)尽量使用java.util.concurrent(jdk 1.5以上)包的并发类代替手写控制并发,比较常用的是ConcurrentHashMap、ConcurrentLinkedQueue、AtomicBoolean等等,实际应用中java.util.concurrent.atomic十分有用,简单方便且效率比使用Lock更高
3)尽量降低锁的使用粒度,尽量不要几个功能用同一把锁
4)尽量减少同步的代码块
线程间的通讯:
其实就是多个线程在操作统一资源。
到时操作的动作不同。
wait;
notify();
notifyAll();
都使用在同步中,因为要对持有监视器(锁)的线程操作。
所以要使用在同步中,因为只有同步才具有锁。
为什么这些操作线程的方法要定义Object类中呢?
因为这些方法在操作同步中线程时,都必须要标识它们所操作线程持有的锁,
只有同一个锁上的被等待线程,可以被同一个锁上的notify唤醒。
不可以对不同锁中的线程进行唤醒。
也就是说,等待和唤醒必须是同一个锁。
而锁可以是任意对象,所以可以被任意对象调用的方法定义在Object类中
多线程之间的相互唤醒
对于多个生产者和消费者。
为什么要定义while判断标记。
原因:让别唤醒的线程在一次盘算标记。
为什么定义notifyAll。
因为需要唤醒对方线程。
因为只有notify,容易出现只唤醒本方线程的情况,导致程序中的所有线程都等待。
JSK1.5中提供了多线程升级解决方案。
将同步synchronized替换成显示的lock操作。
将Object中的wait,notify notifyAll,替换了Condition对象。
该对象可以Lock锁进行获取。
该示例中,实现了本方只唤醒对方操作。
在多线程中懒汉式的运用
懒汉式,使用的锁是文件字节码对象。类名.class
懒汉式特点在于实例的延迟加载 多线程访问懒汉式时,容易出现安全问题。
解决方式,用同步来解决 synchronized 同步代码块或者同步函数都行!
但是有些低效,可以用双重判断来解决,减少对锁的判断。
多线程的应用
在开发是,多线程常用到的创建方式!
线程的总结(二)
死锁:
同步中嵌套同步,而锁却不同!
实际团体协作开发,各个模块交叉调用(持有了一个锁后调用其他模块的方法,而其他模块的方法又需要持有锁),相互等待就有可能会出现死锁,因为本来模块相互调用一般不关心具体实现,只依赖于接口
解决方式:
1)尽量使用tryLock(long timeout, TimeUnit unit)的方法(ReentrantLock、ReentrantReadWriteLock),设置超时时间,超时可以退出防止死锁。
2)尽量使用java.util.concurrent(jdk 1.5以上)包的并发类代替手写控制并发,比较常用的是ConcurrentHashMap、ConcurrentLinkedQueue、AtomicBoolean等等,实际应用中java.util.concurrent.atomic十分有用,简单方便且效率比使用Lock更高
3)尽量降低锁的使用粒度,尽量不要几个功能用同一把锁
4)尽量减少同步的代码块
class Ticket implements Runnable { private int tick = 100; Object obj = new Object(); boolean flag = true; public void run() { if(flag) { while(true) { synchronized(obj) { show(); } } } else while(true) show(); } public synchronized void show() { synchronized(obj) { if(tick>0) { try{Thread.sleep(10);}catch(Exception e){} System.out.println(Thread.currentThread().getName()+"..code :"+tick--); } } } } class DeadLockDemo { public static void main(String[] args) { Ticket t = new Ticket(); Thread t1 = new Thread(t);//创建一个线程 Thread t2 = new Thread(t); t1.start(); try{Thread.sleep(10);}catch(Exception e){} t.flag = false; t2.start(); } }
线程间的通讯:
其实就是多个线程在操作统一资源。
到时操作的动作不同。
wait;
notify();
notifyAll();
都使用在同步中,因为要对持有监视器(锁)的线程操作。
所以要使用在同步中,因为只有同步才具有锁。
为什么这些操作线程的方法要定义Object类中呢?
因为这些方法在操作同步中线程时,都必须要标识它们所操作线程持有的锁,
只有同一个锁上的被等待线程,可以被同一个锁上的notify唤醒。
不可以对不同锁中的线程进行唤醒。
也就是说,等待和唤醒必须是同一个锁。
而锁可以是任意对象,所以可以被任意对象调用的方法定义在Object类中
class Res { private String name; private String sex; private boolean flag = false; public synchronized void set(String name, String sex) { if(flag) try{this.wait();}catch(Exception e){} this.name = name; this.sex = sex; flag = true; this.notify(); } public synchronized void out() { if(!flag) try{this.wait();}catch(Exception e){} System.out.println(name+"..."+sex); flag = false; this.notify(); } } class Input implements Runnable { private Res r; Input(Res r) { this.r = r; } public void run() { int x = 0; while (true) { if(x==0) r.set("mike","man"); else r.set("丽丽","女女女女女"); x = (x+1)%2; } } } class Output implements Runnable { private Res r; Output(Res r) { this.r = r; } public void run() { while(true) { r.out(); } } } class InputOutputDemo { public static void main(String[] args) { Res r = new Res(); new Thread(new Input(r)).start(); new Thread(new Output(r)).start(); /* Input in = new Input(r); Output out = new Output(r); Thread t1 = new Thread(in); Thread t2 = new Thread(out); t1.start(); t2.start(); */ } }
多线程之间的相互唤醒
对于多个生产者和消费者。
为什么要定义while判断标记。
原因:让别唤醒的线程在一次盘算标记。
为什么定义notifyAll。
因为需要唤醒对方线程。
因为只有notify,容易出现只唤醒本方线程的情况,导致程序中的所有线程都等待。
JSK1.5中提供了多线程升级解决方案。
将同步synchronized替换成显示的lock操作。
将Object中的wait,notify notifyAll,替换了Condition对象。
该对象可以Lock锁进行获取。
该示例中,实现了本方只唤醒对方操作。
class Resource private String name; private int count = 1; private boolean flag = false; private Lock lock = new ReentrantLock(); private Condition condition_pro = lock.newCondition(); private Condition condition_con = lock.newCondition(); public void set(String name)throws InterruptedException { lock.lock(); try { while(flag) condition_pro.await(); this.name = name+"--"+count++; System.out.println(Thread.currentThread().getName()+"...生产者..."+this.name); flag = true; condition_con.signal(); } finally { lock.unlock();//释放锁的动作一定要执行! } } public void out()throws InterruptedException { lock.lock(); try { while(!flag) condition_con.await(); System.out.println(Thread.currentThread().getName()+"...消费者......"+this.name); flag = false; condition_pro.signal(); } finally { lock.unlock(); } } } class Producer implements Runnable { private Resource res; Producer(Resource res) { this.res = res; } public void run() { while (true) { try { res.set("+商品+"); } catch (InterruptedException e) { } } } } class Consumer implements Runnable { private Resource res; Consumer(Resource res) { this.res = res; } public void run() { while (true) { try { res.out(); } catch (InterruptedException e) { } } } 4000 } class ProducerConsumerDemo { public static void main(String[] args) { Resource r = new Resource(); Producer pro = new Producer(r); Consumer con = new Consumer(r); Thread t1 = new Thread(pro); Thread t2 = new Thread(pro); Thread t3 = new Thread(con); Thread t4 = new Thread(con); t1.start(); t2.start(); t3.start(); t4.start(); } }
在多线程中懒汉式的运用
懒汉式,使用的锁是文件字节码对象。类名.class
懒汉式特点在于实例的延迟加载 多线程访问懒汉式时,容易出现安全问题。
解决方式,用同步来解决 synchronized 同步代码块或者同步函数都行!
但是有些低效,可以用双重判断来解决,减少对锁的判断。
class Singe { private static Single s = null; private Single(){} public static Single getInstance() { if(s==null) { synchronized(Single.class) { if (s==null) s = new Single(); } } return s; } } class SingleDemo { public static void main(String[] args) { System.out.println("Hello World!"); } }
多线程的应用
在开发是,多线程常用到的创建方式!
class ThreadTest2 { public static void main(String[] args) { new Thread()//匿名内部类 { public void run() { for (int x = 0;x < 100 ;x++ ) { System.out.println(Thread.currentThread().getName()+"....."+x); } } }.start(); for (int x = 0;x < 100 ;x++ ) { System.out.println(Thread.currentThread().getName()+"....."+x); } Runnable r = new Runnable() { public void run() { for (int x = 0;x < 100 ;x++ ) { System.out.println(Thread.currentThread().getName()+"....."+x); } } }; new Thread(r).start(); } }
相关文章推荐
- 黑马程序员——多线程(线程安全、线程间通信、1.5中的Lock)总结2
- 黑马程序员--关于线程的一些笔记总结
- 黑马程序员---java线程Timer学习与总结
- 黑马程序员-------------多线程中的(线程、线程组、线程池、以及Java的设计模式)概念及方法的总结
- 黑马程序员——对线程的一些总结
- 黑马程序员-线程知识总结-No.02
- 黑马程序员——Java基础---线程的另一个总结(4)--线程通信(互斥),线程范围的共享变量
- 黑马程序员--线程总结
- 黑马程序员-----java中你必须掌握的线程技术一DAY15总结
- 黑马程序员——Java基础---线程的另一个总结(2)--定时器
- 黑马程序员——关于线程的总结
- 黑马程序员java学习日记六 线程的学习总结
- 黑马程序员 Java自学总结十一 线程
- 黑马程序员-----java线程学习与总结
- 黑马程序员-关于线程学习的若干总结
- 黑马程序员_线程总结
- 黑马程序员:Java基础总结----线程池及java5的线程并发库
- 黑马程序员_线程总结2
- 黑马程序员——线程的总结(一)
- 黑马程序员——Java基础---线程的另一个总结(3)--互斥,线程锁