-----------------------------------------------------------------android培训、java培训、期待与您交流! ---------------------------------------------------------------
1. 多线程的安全问题:synchronized(同步问题)
① 多线程同步代码块
② 多线程同步函数 :同步关键字作为修饰符修饰函数
同步代码块:
synchronized(对象)
{
需要被同步的代码
}
同步的前提(重要)
1. 必须有两个或两个以上线程
2. 必须是多个线程使用同一个锁
同步代码块弊端:因为线程每次都要对锁进行判断,比较消耗资源(该消耗在使用允许范围内)
同步函数
当synchronized修饰函数时,并没有指定锁,其默认的锁为this
如果同步函数被static静态修饰时,因为静态方法中还没有this(即还没有对象),静态进内存中还没有本类对象,但是一定有该类对应的字节码文件对象-----即:类名.class 该对象的类型是Class,使用可以使用该类对象.clsss文件为锁
懒汉式的安全问题
//饿汉式 class Single { private static final Single s = new Single(); private Single(){} public static Single getInstance() { return s; } }因为饿汉式在开始时就已经创建了Single实例,所以并不会出现多线程的安全问题
//懒汉式---存在多线程安全问题 class Single { private static Single s = null; private Single() {} public static Single getInstance() { if(s == null) s = new Single(); return s; } }在多线程情况下,判断single对象是否存在时就有安全隐患所以需要加锁同步
//懒汉式安全方法 class Single { private static Single s = null; private Single() {} public static Single getInstance() { if(s == null) { synchronized(Single.class) {//静态方法的锁没有this,使用该类所属的字节码文件对象作为锁 if(s == null) s = new Single(); } } return s; } }
线程通信同步安全问题
/* 线程通信优化 */ 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(this.name + "=============" + this.sex); flag = false; this.notify(); } } class Output implements Runnable { Res r; Output(Res r) { this.r = r; } public void run() { while(true) { r.out(); } } } class Input implements Runnable { Res r; Input(Res r) { this.r = r; } public void run() { int x = 0; while(true) { if(x == 0) r.set("Tom", "man"); else r.set("丽丽", "女女女女女女"); x = (x + 1) % 2; } } } class InputOutputDemo2 { public static void main(String[] args) { Res r = new Res(); Input in = new Input(r); Output out = new Output(r); Thread t1 = new Thread(in); Thread t2 = new Thread(out); t1.start(); t2.start(); } }在两个线程通信时,使用同步共享资源后通过等待和唤醒完成了线程通信
线程通信共享问题----等待唤醒机制
wait()
notify()
notifyAll()
wait()与notify(),notifyAll()----并不是Tread类中的,而是其父类Object里的,且该三个方法一般用于同步代码中----并且需要标识其对应的锁
为什么该三个方法定义在Object类中呢?
因为当你在同步代码时要标识他们所操作线程所操作的锁,而这个锁不一定唯一可以是任意对象,所以放在所有类的父类Object。
多个生产者消费者同步共享安全问题---------while循环和notifyAll()
当多个线程操作共享数据时通过上边的两个线程通信if判断标识,notify唤醒线程会出现安全问题所以需改进代码
class Resource { private String name; private int count = 1; private boolean flag = false; public synchronized void set(String name) { while(flag)//if改用while循环判断 try{this.wait();}catch(Exception e) {} this.name = name + "=====" + count++; System.out.println(Thread.currentThread().getName() + "-----------Producer----------" + this.name); flag = true; this.notifyAll();//唤醒等待队列的所有线程 } public synchronized void out() { while(!flag)//if改用while循环判断 try{this.wait();}catch(Exception e) {} System.out.println(Thread.currentThread().getName() + "------Consumer-----" + this.name); flag = false; this.notifyAll();//唤醒等待队列的所有线程 } } class Producer implements Runnable { private Resource r; Producer(Resource r){ this.r = r; } public void run () { while(true) { r.set("Product : Tool"); } } } class Consumer implements Runnable { private Resource r; Consumer(Resource r){ this.r = r; } public void run() { while(true) { r.out(); } } } class ProducerConsumerDemo { public static void main(String[] args) { Resource r = new Resource(); Producer producer = new Producer(r); Consumer consumer = new Consumer(r); Thread proThread1 = new Thread(producer); Thread proThread2 = new Thread(producer); Thread conThread1 = new Thread(consumer); Thread conThread2 = new Thread(consumer); proThread1.start(); proThread2.start(); conThread1.start(); conThread2.start(); } }
多个生产者消费者同步共享JDK1.5 新特性---------java.util.concurrent.locks---Lock接口----Condition接口
Lock接口替代synchronized
Condition接口替代Object的wait,notify,notifyAll-----------使用方法await,signal,signalAll
Lock接口三个实现类
|--ReentrantLock
|--ReentrantReadWriteLock.ReadLock
|--ReenttrantReadWriteLock.WriteLock
用JDK1.5的Lock锁改动多个线程同步的代码
//这只是对原来代码的改用并没有用到新的特点 import java.util.concurrent.locks.*; class Resource { private String name; private int count = 1; private boolean flag = false; //创建锁 private Lock lock = new ReentrantLock(); private Condition condition = lock.newCondition(); public void set(String name) throws InterruptedException { lock.lock(); try { while(flag) //try{this.wait();}catch(Exception e) {} condition.await(); this.name = name + "=====" + count++; System.out.println(Thread.currentThread().getName() + "-----------Producer----------" + this.name); flag = true; //this.notifyAll(); condition.signalAll(); } finally {//因为锁是资源最后一定要释放 lock.unlock(); } } public void out() throws InterruptedException{ lock.lock(); try { while(!flag) //try{this.wait();}catch(Exception e) {} condition.await(); System.out.println(Thread.currentThread().getName() + "------Consumer-----" + this.name); flag = false; //this.notifyAll(); condition.signalAll(); } finally { lock.unlock(); } } } class Producer implements Runnable { private Resource r; Producer(Resource r){ this.r = r; } public void run () { while(true) { try { r.set("Product : Tool"); } catch(InterruptedException e) { } } } } class Consumer implements Runnable { private Resource r; Consumer(Resource r){ this.r = r; } public void run() { while(true) { try { r.out(); } catch(InterruptedException e) { } } } } class ProducerConsumerJDKenhanceDemo { public static void main(String[] args) { Resource r = new Resource(); Producer producer = new Producer(r); Consumer consumer = new Consumer(r); Thread proThread1 = new Thread(producer); Thread proThread2 = new Thread(producer); Thread conThread1 = new Thread(consumer); Thread conThread2 = new Thread(consumer); proThread1.start(); proThread2.start(); conThread1.start(); conThread2.start(); } }
await与signal 不同于wait与notify
await可以等待指定的condition
signal可以唤醒指定的condition
所以新版本的Lock实现同步代码如下
import java.util.concurrent.locks.*; class Resource { private String name; private int count = 1; private boolean flag = false; //创建锁 private Lock lock = new ReentrantLock(); private Condition conditionProducter = lock.newCondition(); private Condition conditionConsumer = lock.newCondition(); public void set(String name) throws InterruptedException { lock.lock(); try { while(flag) //try{this.wait();}catch(Exception e) {} conditionProducter.await(); this.name = name + "=====" + count++; System.out.println(Thread.currentThread().getName() + "-----------Producer----------" + this.name); flag = true; //this.notifyAll(); conditionConsumer.signal(); } finally {//因为锁是资源最后一定要释放 lock.unlock(); } } public void out() throws InterruptedException{ lock.lock(); try { while(!flag) //try{this.wait();}catch(Exception e) {} conditionConsumer.await(); System.out.println(Thread.currentThread().getName() + "------Consumer-----" + this.name); flag = false; //this.notifyAll(); conditionProducter.signal(); } finally { lock.unlock(); } } } class Producer implements Runnable { private Resource r; Producer(Resource r){ this.r = r; } public void run () { while(true) { try { r.set("Product : Tool"); } catch(InterruptedException e) { } } } } class Consumer implements Runnable { private Resource r; Consumer(Resource r){ this.r = r; } public void run() { while(true) { try { r.out(); } catch(InterruptedException e) { } } } } class ProducerConsumerJDKenhanceDemo2 { public static void main(String[] args) { Resource r = new Resource(); Producer producer = new Producer(r); Consumer consumer = new Consumer(r); Thread proThread1 = new Thread(producer); Thread proThread2 = new Thread(producer); Thread conThread1 = new Thread(consumer); Thread conThread2 = new Thread(consumer); proThread1.start(); proThread2.start(); conThread1.start(); conThread2.start(); } }
停止线程
原有的stop方法已经过时,如何停止线程?
只有一种方法,run方法结束。
开启多线程运行,运行代码通常是循环结构,只要控制循环,就可以让run方法结束,也就是线程结束。
代码操作----在循环中使用boolean型标记,对外提供一个修改标记方法
特殊情况:
多线程中当线程冻结时,不会读到标记,线程就无法停止
如何解决这个问题?
interrupt对冻结状态清除,强制让线程回复到运行状态中,这样就可以修改标记,让线程结束
守护线程(后台线程)
setDanmon()设置成守护线程---必须在线程启动前设置
join方法
当A线程执行到了B线程的join方法时,A线程等待,等B线程执行完,A才会执行
Join可以临时加入线程
线程优先级----1---10
默认优先级5
可以通过setPriority()设置线程优先级
MAX_PRIORITY
MIN_PRIORITY
NORM_PRIORITY
yield(): 暂停当前正在执行的线程对象,并执行其他线程。