java多线程学习(六)

总结:

本篇主要介绍

缓存池对线程的影响,

同步方法阻塞问题,

死锁

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多线程编程核心技术>

猜你喜欢

转载自blog.csdn.net/qq467215628/article/details/80211190