总结:
本篇主要介绍
缓存池对线程的影响,
同步方法阻塞问题,
死锁
1,String的常量缓存池对线程的影响
因为字符串在缓存池中是同一个对象,所以一般情况下synchronized代码块不使用String作为锁对象,而改用不在缓存的new Object(),
示例:
package chapter2.stringAndSyn; /* * 演示String常量池造成的线程问题: * 因为a和b线程都使用"AA"作为参数,两个线程持有相同的锁, * 这个字符串在缓存池中是同一个对象,所以b线程会被a线程阻塞 * 如果将b线程的参数改成其他字符串,则可以并发执行, * 所以一般情况下synchronized代码块不使用String作为锁对象, * 而改用不在缓存的new Object() * 输出为: * a a a a a */ public class Run { public static void main(String[] args) { Service service=new Service(); ThreadA ta=new ThreadA(service); ta.setName("a"); ta.start(); ThreadB tb=new ThreadB(service); tb.setName("b"); tb.start(); } } package chapter2.stringAndSyn; public class Service { public static void print(String stringParam){ try { synchronized (stringParam) { while(true){ System.out.println(Thread.currentThread().getName()); Thread.sleep(1000); } } } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } package chapter2.stringAndSyn; public class ThreadA extends Thread { private Service service; public ThreadA(Service service) { super(); this.service=service; } @Override public void run() { super.run(); service.print("AA"); } } package chapter2.stringAndSyn; public class ThreadB extends Thread { private Service service; public ThreadB(Service service) { super(); this.service=service; } @Override public void run() { super.run(); service.print("AA"); // service.print("BB"); } }
修改后的为:
package chapter2.stringAndSyn2; /* *演示用new Object()方式替换String作为锁对象后解决线程阻塞的问题 * 输出为: a b a b a b */ public class Run { public static void main(String[] args) { Service service=new Service(); ThreadA ta=new ThreadA(service); ta.setName("a"); ta.start(); ThreadB tb=new ThreadB(service); tb.setName("b"); tb.start(); } } package chapter2.stringAndSyn2; public class Service { public static void print(Object object){ try { synchronized (object) { while(true){ System.out.println(Thread.currentThread().getName()); Thread.sleep(1000); } } } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } package chapter2.stringAndSyn2; public class ThreadA extends Thread { private Service service; public ThreadA(Service service) { super(); this.service=service; } @Override public void run() { super.run(); service.print(new Object()); } } package chapter2.stringAndSyn2; public class ThreadB extends Thread { private Service service; public ThreadB(Service service) { super(); this.service=service; } @Override public void run() { super.run(); service.print(new Object()); } }
同步synchronized方法无线等待及解决
package chapter2.twoStop; /* *演示同步方法之间造成死循环的问题, *同一个类的不同同步方法是同步的,锁对象是类实例,b线程需要等待a线程执行完成,释放锁才有机会执行 *如果两个方法之间没有依赖,可以改为同步块,对两个不同的对象加锁,解决阻塞的问题 * 输出为: methodA begin 后面一直卡死这边 */ public class Run { public static void main(String[] args) { Service service=new Service(); ThreadA ta=new ThreadA(service); ta.setName("a"); ta.start(); ThreadB tb=new ThreadB(service); tb.setName("b"); tb.start(); } } package chapter2.twoStop; public class Service { synchronized public void methodA(){ System.out.println("methodA begin"); boolean isContinue=true; while(isContinue){ } System.out.println("methodA end"); } synchronized public void methodB(){ System.out.println("methodB begin"); System.out.println("methodB end"); } } package chapter2.twoStop; public class ThreadA extends Thread { private Service service; public ThreadA(Service service) { super(); this.service=service; } @Override public void run() { super.run(); service.methodA(); } } package chapter2.twoStop; public class ThreadB extends Thread { private Service service; public ThreadB(Service service) { super(); this.service=service; } @Override public void run() { super.run(); service.methodB(); } }
解决为:
package chapter2.twoNoStop; /* *演示使用同步块,对不同对象加锁,解决同步方法间的阻塞问题 * 输出为: methodA begin methodB begin methodB end 后面一直执行methodA的循环,b线程没有呗阻塞 */ public class Run { public static void main(String[] args) { Service service=new Service(); ThreadA ta=new ThreadA(service); ta.setName("a"); ta.start(); ThreadB tb=new ThreadB(service); tb.setName("b"); tb.start(); } } package chapter2.twoNoStop; public class Service { Object obj1=new Object(); public void methodA(){ synchronized (obj1) { System.out.println("methodA begin"); boolean isContinue=true; while(isContinue){ } System.out.println("methodA end"); } } Object obj2=new Object(); public void methodB(){ synchronized (obj2) { System.out.println("methodB begin"); System.out.println("methodB end"); } } }
死锁
可以在程序执行的时候,使用jdk/bin下面的jsp和jstack -l 命令查看是否有死锁
package chapter2.deadLockTest; /* * 演示死锁出现的情况 * a线程先获取到lock1的锁,然后在sleep的时候,b线程获取到lock2的锁, * a线程sleep后,需要获取lock2锁,而此锁在b手上,需要等其释放,且a一直持有lock1锁 * b持有lock2,等待lock1, * a,b相互等待,形成死锁 * 输出为: * username=a username=b 后面一直卡死 */ public class Run { public static void main(String[] args) { try { DealThread dt=new DealThread(); dt.setFlag("a"); Thread t1=new Thread(dt); t1.start(); Thread.sleep(100); dt.setFlag("b"); Thread t2=new Thread(dt); t2.start(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } package chapter2.deadLockTest; public class DealThread implements Runnable { public String username; public Object lock1=new Object(); public Object lock2=new Object(); public void setFlag(String username){ this.username=username; } @Override public void run() { if(username.equals("a")){ synchronized (lock1) { try { System.out.println("username="+username); Thread.sleep(3000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } synchronized (lock2) { System.out.println("按lock1->lock2的代码顺序执行了"); } } } if(username.equals("b")){ synchronized (lock2) { try { System.out.println("username="+username); Thread.sleep(3000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } synchronized (lock1) { System.out.println("按lock2->lock1的代码顺序执行了"); } } } } }
参考:<java多线程编程核心技术>