1.不加任何同步措施
package jianzhioffer;
//出现不安全问题
/**
* 吐钱成功,吐出钞票:800.0
吐钱成功,吐出钞票:800.0
余额为:200.0
余额为:-600.0
*/
class Account{ public String accountNo; public double balance; public Account(String accountNo,double balance){ this.accountNo=accountNo; this.balance=balance; } public int hashcode(){ return accountNo.hashCode(); } public boolean equals(Object obj){ if(obj!=null&&obj.getClass()==Account.class){ Account target=(Account)obj; return target.accountNo.equals(accountNo); } return false; } } class DrawThread extends Thread{ public Account account; public double drawAmount; public DrawThread(String name,Account account,double drawAmount){ super(name); this.account=account; this.drawAmount=drawAmount; } public void run(){ if(account.balance>=drawAmount){ System.out.println("吐钱成功,吐出钞票:"+drawAmount); try{ Thread.sleep(1); }catch(InterruptedException ex){ ex.printStackTrace(); } account.balance=account.balance-drawAmount; System.out.println("余额为:"+account.balance); }else{ System.out.println(getName()+"取钱失败,余额不足"); } } } public class testSynchronize1 extends Thread{ public static void main(String[] args) throws InterruptedException { Account acc=new Account("1234567", 1000); new DrawThread("甲",acc,800).start(); // Thread.sleep(100); new DrawThread("已",acc,800).start(); } }
2. 使用同步代码块
package jianzhioffer; class Account{ public String accountNo; public double balance; public Account(String accountNo,double balance){ this.accountNo=accountNo; this.balance=balance; } public int hashcode(){ return accountNo.hashCode(); } public boolean equals(Object obj){ if(obj!=null&&obj.getClass()==Account.class){ Account target=(Account)obj; return target.accountNo.equals(accountNo); } return false; } } class DrawThread extends Thread{ public Account account; public double drawAmount; public DrawThread(String name,Account account,double drawAmount){ super(name); this.account=account; this.drawAmount=drawAmount; } public void run(){ //1.同步代码块,account是同步监视器,在执行这个代码块之前锁定account synchronized(account){ if(account.balance>=drawAmount){ System.out.println("吐钱成功,吐出钞票:"+drawAmount); try{ Thread.sleep(1); }catch(InterruptedException ex){ ex.printStackTrace(); } account.balance=account.balance-drawAmount; System.out.println("余额为:"+account.balance); }else{ System.out.println(getName()+"取钱失败,余额不足"); } } //同步代码块结束,释放同步锁(同步监视器account) } } public class testSynchronize1 extends Thread{ public static void main(String[] args) throws InterruptedException { Account acc=new Account("1234567", 1000); new DrawThread("甲",acc,800).start(); // Thread.sleep(100); new DrawThread("已",acc,800).start(); } }
3.使用同步方法
package jianzhioffer; class Account{ public String accountNo; public double balance; public Account(String accountNo,double balance){ this.accountNo=accountNo; this.balance=balance; } public int hashcode(){ return accountNo.hashCode(); } public boolean equals(Object obj){ if(obj!=null&&obj.getClass()==Account.class){ Account target=(Account)obj; return target.accountNo.equals(accountNo); } return false; } //监视器是this,对于同一个账户,一次只有一个线程可以获得的对account的锁定,然后进入draw方法进行取钱 public synchronized void draw(double drawAmount){ if(balance>=drawAmount){ System.out.println("吐钱成功,吐出钞票:"+drawAmount); try{ Thread.sleep(1); }catch(InterruptedException ex){ ex.printStackTrace(); } balance-=drawAmount; System.out.println("余额为:"+balance); }else{ System.out.println(Thread.currentThread().getName()+"取钱失败,余额不足"); } } } class DrawThread extends Thread{ public Account account; public double drawAmount; public DrawThread(String name,Account account,double drawAmount){ super(name); this.account=account; this.drawAmount=drawAmount; } public void run(){ account.draw(drawAmount); } } public class testSynchronize1 extends Thread{ public static void main(String[] args) throws InterruptedException { Account acc=new Account("1234567", 1000); new DrawThread("甲",acc,800).start(); // Thread.sleep(100); new DrawThread("已",acc,800).start(); } }
同步监视器的释放:
a.执行结束
b.break,return
c.error
d.执行了同步监视器的wait()
不会释放的情况
a.sleep(),yeild()
b. suspend挂起
4. 同步锁
package jianzhioffer; import java.util.concurrent.locks.ReentrantLock; class Account { public String accountNo; public double balance; //可重入锁 public final ReentrantLock lock = new ReentrantLock(); public Account(String accountNo, double balance) { this.accountNo = accountNo; this.balance = balance; } public int hashcode() { return accountNo.hashCode(); } public boolean equals(Object obj) { if (obj != null && obj.getClass() == Account.class) { Account target = (Account) obj; return target.accountNo.equals(accountNo); } return false; } public void draw(double drawAmount) throws InterruptedException { //加上锁 lock.lock(); try { if (balance >= drawAmount) { System.out.println("吐钱成功,吐出钞票:" + drawAmount); try { Thread.sleep(1); } catch (InterruptedException ex) { ex.printStackTrace(); } balance -= drawAmount; System.out.println("余额为:" + balance); } else { System.out.println(Thread.currentThread().getName() + "取钱失败,余额不足"); } } finally { //在finally中去掉锁确保可释放 lock.unlock(); } } } class DrawThread extends Thread { public Account account; public double drawAmount; public DrawThread(String name, Account account, double drawAmount) { super(name); this.account = account; this.drawAmount = drawAmount; } public void run() { try { account.draw(drawAmount); } catch (InterruptedException e) { e.printStackTrace(); } } } public class testSynchronize1 extends Thread{ public static void main(String[] args) throws InterruptedException { Account acc=new Account("1234567", 1000); new DrawThread("甲",acc,800).start(); // Thread.sleep(100); new DrawThread("已",acc,800).start(); } }
5.死锁
package jianzhioffer; class A{ public synchronized void foo(B b){ System.out.println("当前线程名:"+Thread.currentThread().getName()+"进入了A实例的foo方法"); try{ Thread.sleep(200); }catch(InterruptedException e){ e.printStackTrace(); } System.out.println("当前线程名:"+Thread.currentThread().getName()+"企图调用B的last方法"); b.last(); } public synchronized void last(){ System.out.println("进入了A的last内部"); } } class B{ public synchronized void foo(A a){ System.out.println("当前线程名:"+Thread.currentThread().getName()+"进入了B实例的foo方法"); try{ Thread.sleep(200); }catch(InterruptedException e){ e.printStackTrace(); } System.out.println("当前线程名:"+Thread.currentThread().getName()+"企图调用A的last方法"); a.last(); } public synchronized void last(){ System.out.println("进入了B的last内部"); } } public class DeadLock implements Runnable{ A a=new A(); B b=new B(); public void init(){ Thread.currentThread().setName("主线程"); a.foo(b); System.out.println("进入主线程之后"); } @Override public void run() { Thread.currentThread().setName("副线程"); b.foo(a); System.out.println("进入副线程之后"); } public static void main(String[] args) { DeadLock dl=new DeadLock(); //以dl为target启动新线程 new Thread(dl).start(); //通过init()方法作为新线程 dl.init(); } }
一定要两个方法都是同步方法
package jianzhioffer; import java.util.Date; public class DeadLock2 { public static String obj1="obj1"; public static String obj2="obj2"; public static void main(String[] args) { LockA la=new LockA(); new Thread(la).start(); LockB lb=new LockB(); new Thread(lb).start(); } } class LockA implements Runnable{ @Override public void run() { // TODO Auto-generated method stub try{ System.out.println(new Date().toString()+"LockA开始执行"); while(true){ synchronized(DeadLock2.obj1){ System.out.println(new Date().toString()+"LockA锁住了obj1"); Thread.sleep(300);//给B锁住机会 synchronized(DeadLock2.obj2){ System.out.println(new Date().toString()+"LockA锁住了obj2"); Thread.sleep(60000);//占用了就不放,为了测试 } } } }catch(Exception e){ e.printStackTrace(); } } } class LockB implements Runnable{ @Override public void run() { // TODO Auto-generated method stub try{ System.out.println(new Date().toString()+"LockB开始执行"); synchronized(DeadLock2.obj2){ System.out.println(new Date().toString()+"LockB锁住了obj2"); Thread.sleep(300); synchronized(DeadLock2.obj1){ System.out.println(new Date().toString()+"LockB锁住了obj1"); Thread.sleep(60000);//占用了就不放,为了测试 } } }catch(Exception e){ e.printStackTrace(); } } }
解决方法
package jianzhioffer; import java.util.Date; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; public class unlock { public static String obj1 = "obj1"; public static final Semaphore a1 = new Semaphore(1); public static String obj2 = "obj2"; public static final Semaphore a2 = new Semaphore(1); public static void main(String[] args) { LockAa la = new LockAa(); new Thread(la).start(); LockBa lb = new LockBa(); new Thread(lb).start(); } } class LockAa implements Runnable { @Override public void run() { try { System.out.println(new Date().toString() + " LockA 开始执行"); while (true) { if (unlock.a1.tryAcquire(1, TimeUnit.SECONDS)) { System.out.println(new Date().toString() + " LockA 锁住 obj1"); if (unlock.a2.tryAcquire(1, TimeUnit.SECONDS)) { System.out.println(new Date().toString() + " LockA 锁住 obj2"); Thread.sleep(60 * 1000); // do something }else{ System.out.println(new Date().toString() + "LockA 锁 obj2 失败"); } }else{ System.out.println(new Date().toString() + "LockA 锁 obj1 失败"); } unlock.a1.release(); // 释放 unlock.a2.release(); Thread.sleep(1000); // 马上进行尝试,现实情况下do something是不确定的 } } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } class LockBa implements Runnable { @Override public void run() { try { System.out.println(new Date().toString() + " LockB 开始执行"); while (true) { if (unlock.a2.tryAcquire(1, TimeUnit.SECONDS)) { System.out.println(new Date().toString() + " LockB 锁住 obj2"); if (unlock.a1.tryAcquire(1, TimeUnit.SECONDS)) { System.out.println(new Date().toString() + " LockB 锁住 obj1"); Thread.sleep(60 * 1000); // do something }else{ System.out.println(new Date().toString() + "LockB 锁 obj1 失败"); } }else{ System.out.println(new Date().toString() + "LockB 锁 obj2 失败"); } unlock.a1.release(); // 释放 unlock.a2.release(); Thread.sleep(1000); // 马上进行尝试,现实情况下do something是不确定的 } } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
进程间协调-存款取款轮换 - 针对synchronized关键字,因为存在同步监视器监视account
package jianzhioffer; import java.util.concurrent.locks.ReentrantLock; class Account { public String accountNo; public double balance; //可重入锁 public boolean flag=false;//是否有人存钱 public Account(String accountNo, double balance) { this.accountNo = accountNo; this.balance = balance; } public int hashcode() { return accountNo.hashCode(); } public boolean equals(Object obj) { if (obj != null && obj.getClass() == Account.class) { Account target = (Account) obj; return target.accountNo.equals(accountNo); } return false; } public synchronized void draw(double drawAmount) throws InterruptedException { try { if(!flag){ //没人存钱,等待 wait(); }else{ System.out.println(Thread.currentThread().getName()+"取钱:"+drawAmount); balance-=drawAmount; System.out.println("余额为:" + balance); flag=false;//转给存款 notifyAll(); } } catch(Exception e){ } } public synchronized void deposit(double drawAmount) throws InterruptedException { try{ if(flag){ wait(); }else{ System.out.println(Thread.currentThread().getName()+"存钱 "+drawAmount); balance=balance+drawAmount; System.out.println("账户余额为"+balance); flag=true; notifyAll(); } }catch(Exception e){ e.printStackTrace(); } } } class DrawThread extends Thread { public Account account; public double drawAmount; public DrawThread(String name, Account account, double drawAmount) { super(name); this.account = account; this.drawAmount = drawAmount; } public void run() { try{ for(int i=0;i<100;i++){ account.draw(drawAmount); } }catch(Exception e){ e.printStackTrace(); } } } class Deposit extends Thread { public Account account; public double drawAmount; public Deposit(String name, Account account, double drawAmount) { super(name); this.account = account; this.drawAmount = drawAmount; } public void run() { try{ for(int i=0;i<100;i++){ account.deposit(drawAmount); } }catch(Exception e){ e.printStackTrace(); } } } public class testSynchronize1 extends Thread{ public static void main(String[] args) throws InterruptedException { Account acc=new Account("1234567", 0); new DrawThread("取款者",acc,800).start(); // Thread.sleep(100); new Deposit("存款者甲",acc,800).start(); new Deposit("存款者乙",acc,800).start(); new Deposit("存款者丙",acc,800).start(); } }
使用条件变量控制协调 - 针对用 Lock的因为没有监视器-Condition将wait,notify-变成await,signal
package jianzhioffer; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; class Account { public final ReentrantLock lock=new ReentrantLock(); public final Condition cond=lock.newCondition();//conditioon将wait,notify,notifyall分解成三个截然不同的方法 public String accountNo; public double balance; //可重入锁 public boolean flag=false;//是否有人存钱 public Account(){} public Account(String accountNo, double balance) { this.accountNo = accountNo; this.balance = balance; } public int hashcode() { return accountNo.hashCode(); } public boolean equals(Object obj) { if (obj != null && obj.getClass() == Account.class) { Account target = (Account) obj; return target.accountNo.equals(accountNo); } return false; } public void draw(double drawAmount) throws InterruptedException { lock.lock(); try { if(!flag){ //没人存钱,等待 cond.await(); }else{ System.out.println(Thread.currentThread().getName()+"取钱:"+drawAmount); balance-=drawAmount; System.out.println("余额为:" + balance); flag=false;//转给存款 cond.signalAll(); } } catch(Exception e){ e.printStackTrace(); }finally{ lock.unlock(); } } public void deposit(double drawAmount) throws InterruptedException { lock.lock(); try{ if(flag){ cond.await(); }else{ System.out.println(Thread.currentThread().getName()+"存钱 "+drawAmount); balance=balance+drawAmount; System.out.println("账户余额为"+balance); flag=true; cond.signalAll(); } }catch(Exception e){ e.printStackTrace(); }finally{ lock.unlock(); } } } class DrawThread extends Thread { public Account account; public double drawAmount; public DrawThread(String name, Account account, double drawAmount) { super(name); this.account = account; this.drawAmount = drawAmount; } public void run() { try{ for(int i=0;i<10;i++){ account.draw(drawAmount); } }catch(Exception e){ e.printStackTrace(); } } } class Deposit extends Thread { public Account account; public double drawAmount; public Deposit(String name, Account account, double drawAmount) { super(name); this.account = account; this.drawAmount = drawAmount; } public void run() { try{ for(int i=0;i<10;i++){ account.deposit(drawAmount); } }catch(Exception e){ e.printStackTrace(); } } } public class testSynchronize1 extends Thread{ public static void main(String[] args) throws InterruptedException { Account acc=new Account("1234567", 0); new DrawThread("取款者",acc,800).start(); // Thread.sleep(100); new Deposit("存款者甲",acc,800).start(); new Deposit("存款者乙",acc,800).start(); new Deposit("存款者丙",acc,800).start(); } }
使用管道流通讯PipedInputStream,PipedReader,Pipe.SinkChannel
package jianzhioffer; import java.io.BufferedReader; import java.io.IOException; import java.io.PipedReader; import java.io.PipedWriter; class ReaderThread extends Thread{ public PipedReader pr;//来源 public BufferedReader br; public ReaderThread(){} public ReaderThread(PipedReader pr){ this.pr=pr; this.br=new BufferedReader(pr);//读到buffer } public void run(){ String buf=null; try{ while((buf=br.readLine())!=null){ System.out.println(buf);//输出 } }catch(Exception e){ e.printStackTrace(); }finally{ try{ { if(br!=null){ br.close(); } } }catch(Exception e){ e.printStackTrace(); } } } } class WiterThread extends Thread{ String []books=new String[]{//输入 "aaaaaaaaa", "bbbbbbbbbb", "ccccc", "ddddddd" }; public PipedWriter pw; public WiterThread(){}; public WiterThread(PipedWriter pw){ this.pw=pw; } public void run(){ try{ for(int i=0;i<100;i++){ System.out.println(i); pw.write(books[i%4]+"\n");//读到pw } }catch(Exception e){ e.printStackTrace(); }finally{ try{ if(pw!=null){ pw.close(); } }catch(IOException e){ e.printStackTrace(); } } } } public class PipeCommunication { public static void main(String[] args) { PipedWriter pw=null; PipedReader pr=null; try{ pw=new PipedWriter(); pr=new PipedReader(); pw.connect(pr);//输入输出连接 new WiterThread(pw).start(); new ReaderThread(pr).start(); }catch(Exception e){ e.printStackTrace(); } } }
线程池:
程序将一个runnable对象传给线程池,线程池就启动一条线程执行这个线程的run,执行完该线程不会死亡,回到新城吃成为空闲,等待下一个runnable
存在原因:启动一个线程成本高,涉及与操作系统的交互,在这种情况下,使用线程池可以提高性能,另外可以有效控制并发线程数量,低于抖动阈值
Ececutors工厂用来创建线程池
new CachedThreadPool() - 有缓存功能,,线程被缓存在线程池
new FixedThreadPool(int x):固定线程数量,可重用
new SingleThreadPool(),单独一个线程
new ScheduleThreadPool(int x),指定延迟后执行任务
new SingleThreadScheduleExcecutor(int x),指定延迟后执行任务,单个线程
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; class TestThread implements Runnable{ public void run(){ for(int i=0;i<100;i++){ System.out.println(Thread.currentThread().getName()+"的值为:"+i); } } } public class ThreadPoolTest { public static void main(String[] args) { ExecutorService pool=Executors.newFixedThreadPool(6); pool.submit(new TestThread()); pool.submit(new TestThread()); //shutdown执行完了shutdown, //shutdownNow,试图立刻结束,全部杀死 pool.shutdownNow(); } }