string数据类型使用在synchronized同步代码块中出现的情况。
public class ThreadA extends Thread { private Service service; public ThreadA(Service service) { super(); this.service = service; } @Override public void run() { service.print("AA"); } }
public class ThreadB extends Thread { private Service service; public ThreadB(Service service) { super(); this.service = service; } @Override public void run() { service.print("AA"); } }
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) { e.printStackTrace(); } } }
public static void main(String[] args) { Service service = new Service(); ThreadA a = new ThreadA(service); a.setName("A"); a.start(); ThreadB b = new ThreadB(service); b.setName("B"); b.start(); }
打印的结果A线程一直打印,B线程执行不力,就是因为string的两个值都是一样的,两个线程持有相同的锁,string常量池带来的问题,因此synchronized代码块都不用string作为锁对象,而改用其他的,比如new Object()实例化一个Object对象。
同步synchronized方法无线等待与解决
同步方法容易造成死循环 代码如下举例:
public class Service { synchronized public void methodA() { System.out.println("methodA begin"); boolean isContinueRun = true; while (isContinueRun) { } System.out.println("methodA end"); } synchronized public void methodB() { System.out.println("methodB begin"); System.out.println("methodB end"); } }
public class ThreadA extends Thread { private Service service; public ThreadA(Service service) { super(); this.service = service; } @Override public void run() { service.methodA(); } }
public class ThreadB extends Thread { private Service service; public ThreadB(Service service) { super(); this.service = service; } @Override public void run() { service.methodB(); } }
public static void main(String[] args) { Service service = new Service(); ThreadA athread = new ThreadA(service); athread.start(); ThreadB bthread = new ThreadB(service); bthread.start(); }
线程B永远等不到机会,A线程锁死了,这也是前面反复介绍过的同步带来的问题。这个时候可以用同步块来解决这样的问题。
更改service
public class Service { Object object = new Object(); public void methodA() { synchronized(object){ System.out.println("methodA begin"); boolean isContinueRun = true; while (isContinueRun) { } System.out.println("methodA end"); } } Object object2= new Object(); public void methodB() { synchronized(object2){ System.out.println("methodB begin"); System.out.println("methodB end"); } } }多线程死锁介绍:
不同的线程都在等待根本不可能被释放的锁,从而导致所有的任务否无法继续完成,造成死锁,线程的“假死”。
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代码顺序执行了"); } } } } }
public class Run { public static void main(String[] args) { try { DealThread t1 = new DealThread(); t1.setFlag("a"); Thread thread1 = new Thread(t1); thread1.start(); Thread.sleep(100); t1.setFlag("b"); Thread thread2 = new Thread(t1); thread2.start(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
只打印如下,因为A B都在等待对方释放锁继而继续执行下面的代码,造成了死锁问题。
内部类与同步实验:
扫描二维码关注公众号,回复:
1101496 查看本文章
public class OutClass { static class Inner { public void method1() { synchronized ("其它的锁") { for (int i = 1; i <= 10; i++) { System.out.println(Thread.currentThread().getName() + " i=" + i); try { Thread.sleep(100); } catch (InterruptedException e) { } } } } public synchronized void method2() { for (int i = 11; i <= 20; i++) { System.out .println(Thread.currentThread().getName() + " i=" + i); try { Thread.sleep(100); } catch (InterruptedException e) { } } } } }
public static void main(String[] args) { final Inner inner = new Inner(); Thread t1 = new Thread(new Runnable() { public void run() { inner.method1(); } }, "A"); Thread t2 = new Thread(new Runnable() { public void run() { inner.method2(); } }, "B"); t1.start(); t2.start(); }
打印结果异步执行,两个线程持有不同的对象锁,一把是字符串锁,一把是当前内部类 类锁。
public class OutClass { static class InnerClass1 { public void method1(InnerClass2 class2) { String threadName = Thread.currentThread().getName(); synchronized (class2) { System.out.println(threadName + " 进入InnerClass1类中的method1方法"); for (int i = 0; i < 10; i++) { System.out.println("i=" + i); try { Thread.sleep(100); } catch (InterruptedException e) { } } System.out.println(threadName + " 离开InnerClass1类中的method1方法"); } } public synchronized void method2() { String threadName = Thread.currentThread().getName(); System.out.println(threadName + " 进入InnerClass1类中的method2方法"); for (int j = 0; j < 10; j++) { System.out.println("j=" + j); try { Thread.sleep(100); } catch (InterruptedException e) { } } System.out.println(threadName + " 离开InnerClass1类中的method2方法"); } } static class InnerClass2 { public synchronized void method1() { String threadName = Thread.currentThread().getName(); System.out.println(threadName + " 进入InnerClass2类中的method1方法"); for (int k = 0; k < 10; k++) { System.out.println("k=" + k); try { Thread.sleep(100); } catch (InterruptedException e) { } } System.out.println(threadName + " 离开InnerClass2类中的method1方法"); } } }
public class Run { public static void main(String[] args) { final InnerClass1 in1 = new InnerClass1(); final InnerClass2 in2 = new InnerClass2(); Thread t1 = new Thread(new Runnable() { public void run() { in1.method1(in2); } }, "T1"); Thread t2 = new Thread(new Runnable() { public void run() { in1.method2(); } }, "T2"); // // // // Thread t3 = new Thread(new Runnable() { public void run() { in2.method1(); } }, "T3"); t1.start(); t2.start(); t3.start(); } }
同步代码块对class2上锁后 其他线程只能同步访问class2中的静态同步方法。
T1和T2异步执行,T1和T3同步执行。
锁对象的改变实验:
public class MyService { private String lock = "123"; public void testMethod() { try { synchronized (lock) { System.out.println(Thread.currentThread().getName() + " begin " + System.currentTimeMillis()); lock = "456";//改变锁值 Thread.sleep(2000); System.out.println(Thread.currentThread().getName() + " end " + System.currentTimeMillis()); } } catch (InterruptedException e) { e.printStackTrace(); } } }
public class ThreadA extends Thread { private MyService service; public ThreadA(MyService service) { super(); this.service = service; } @Override public void run() { service.testMethod(); } }
public class ThreadB extends Thread { private MyService service; public ThreadB(MyService service) { super(); this.service = service; } @Override public void run() { service.testMethod(); } }
public static void main(String[] args) throws InterruptedException { MyService service = new MyService(); ThreadA a = new ThreadA(service); a.setName("A"); ThreadB b = new ThreadB(service); b.setName("B"); a.start(); Thread.sleep(50);// 存在50毫秒 b.start(); }
因为A线程获取123这把锁,B线程还没执行,这时A已经改了锁的值,所以B进来也能获取锁 锁是456了已经。
去掉 存在50毫秒这行,打印结果有不一样。
因为A B线程同时抢锁,同时持有的锁是123,所以同步打印。