多线程 续

死锁

死锁:指两个或者两个以上的线程在执行的过程中,因争夺资源产生的一种互相等待现象。

public class ThreadDemo02 {
	public static void main(String[] args) {
		DieLock t1 = new DieLock(true);
		DieLock t2 = new DieLock(false);
		
		t1.start();
		t2.start();
	}
}

class DieLock extends Thread {
	
	// 定义flag标志位用于切换线程执行
	private boolean flag;
	
	public DieLock() {
		super();
	}
	
	public DieLock(boolean flag) {
		super();
		this.flag = flag;
	}

	@Override
	public void run() {
		if (flag) {
			synchronized (MyLock.LOCKA) {
				System.out.println("if语句中的LockA锁");
				synchronized (MyLock.LOCKB) {
					System.out.println("if语句中的LockB锁");
				}
			}
		} else {
			synchronized (MyLock.LOCKB) {
				System.out.println("else语句中的LockB锁");
				synchronized (MyLock.LOCKA) {
					System.out.println("else语句中的LockA锁");
				}
			}
		}
	}

	public boolean isFlag() {
		return flag;
	}

	public void setFlag(boolean flag) {
		this.flag = flag;
	}
} 

class MyLock {
	public static final Object LOCKA = new Object();
	public static final Object LOCKB = new Object();
}

线程池

当程序中要创建大量生存期很短的线程时,应该考虑使用线程池,程序启动一个新线程占用资源大,使用线程池可以很好的提高性能,线程池里的每一个线程代码结束后,并不会死亡,而是再次回到线程池中成为空闲状态,等待下一个对象来使用。

使用Executors 工厂类来产生线程池

​ public static ExecutorService newCachedThreadPool() 创建一个线程池

​ public static ExecutorService newFixedThreadPool(int nThreads) 创建固定线程数的线程池

​ public static ExecutorService newSingleThreadExecutor()

public class ThreadDemo01 {
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		// 创建线程池
		ExecutorService pool = Executors.newFixedThreadPool(3);
		// 将线程放入到池中
		pool.submit(new MyRunnable());
		Future<Integer> future = pool.submit(new MyCallable());
		pool.submit(new Runnable() {
			
			@Override
			public void run() {
				for (int i = 0; i < 100; i++) {
					System.out.println(Thread.currentThread().getName() + "线程池匿名内部类实现Runnable方式开启线程:" + i);
				}
			}
		});
		System.out.println("1~100的和为:" + future.get());
		
		// 结束线程池
		pool.shutdown();
	}
}

class MyRunnable implements Runnable {

	@Override
	public void run() {
		for (int i = 0; i < 100; i++) {
			System.out.println(Thread.currentThread().getName() + "线程池实现Runnable方式开启线程:" + i);
		}
	}
	
}

class MyCallable implements Callable<Integer> {

	@Override
	public Integer call() throws Exception {
		
		int sum = 0;
		for (int i = 1; i <= 100; i++) {
			System.out.println(Thread.currentThread().getName() + "线程池实现Callable方式开启线程:" + i);
			sum += i;
		}
		return sum;
	}
	
}

线程组

本质可以理解为 Thread[] threads.

Thread(ThreadGroup group, Runnable target) 分配新的 Thread 对象到线程组。

Thread(ThreadGroup group, Runnable target, String name) 分配新的 Thread 对象到线程组,并把 给线程命名

Thread(ThreadGroup group, Runnable target, String name, long stackSize) 分分配新的 Thread 对象到线程组,并把 给线程命名,并具有指定的堆栈大小。

Thread(ThreadGroup group, String name) 分配新的 Thread 对象。

public class ThreadDemo02 {
	public static void main(String[] args) {
		
		// 创建小组
		ThreadGroup tg1 = new ThreadGroup("小组1");
		ThreadGroup tg2 = new ThreadGroup("小组2");
		
		MyRunnable mr = new MyRunnable();
		
		Thread t1 = new Thread(tg1, mr, "线程1");
		Thread t2 = new Thread(tg1, mr, "线程2");
		Thread t3 = new Thread(tg1, mr, "线程3");
		
		Thread t4 = new Thread(tg2, mr, "线程4");
		Thread t5 = new Thread(tg2, mr, "线程5");
		Thread t6 = new Thread(tg2, mr, "线程6");
	
		t1.start();
		t2.start();
		t3.start();
		t4.start();
		t5.start();
		t6.start();
		
		System.out.println(tg1.activeCount());
		tg1.setDaemon(true);
		tg1.stop();
		System.out.println(tg1.getName());
		
		// 获取主线程所在的组
		String mainThreadGroupName = Thread.currentThread().getThreadGroup().getName();
		System.out.println(mainThreadGroupName);
		
	}
}

class MyGroupRunnable implements Runnable {

	@Override
	public void run() {
		for (int i = 0; i < 100; i++) {
			System.out.println(Thread.currentThread().getName() + ":" + i);
		}
	}
	
}

线程通信

线程和线程之间实现数据交互

通过构造方法

通过实现Callable接口的方式

接口回调方式传递数据

同步锁串行实现数据传递

利用等待唤醒机制

接口回调
public class ThreadDemo01 {
	public static void main(String[] args) {
		AThread a = new AThread();
		a.setName("A");
		a.start();
		
	}
}

class AThread extends Thread {
	@Override
	public void run() {
		
		BThread b = new BThread();
		b.setName("B");
		b.setCb(new ICallBack() {
			
			@Override
			public int fun(int a, int b, String message) {
				int sum = a + b;
				System.out.println("收到了来自于B线程的消息: " + message);
				return sum;
			}
		});
		b.start();
		
		for (int i = 0; i < 100; i++) {
			System.out.println(Thread.currentThread().getName() + "线程正在执行!");
		}
		
	}
}

class BThread extends Thread {
	
	private ICallBack cb;
	
	public BThread() {}
	
	public BThread(String name, ICallBack cb) {
		super(name);
		this.cb = cb;
	}
	
	public void setCb(ICallBack cb) {
		this.cb = cb;
	}
	
	@Override
	public void run() {
		for (int i = 0; i < 100; i++) {
			System.out.println(Thread.currentThread().getName() + "线程正在执行!");
		}
		// 这里你想要传递什么数据就通过实参,实参你可以自己任意的确定 B->A
		int result = cb.fun(10, 20, "B给A两个整数");
		// 这里的result是 A线程【调用者】传递给B线程 A->B
		System.out.println("收到了来自于A线程的数据: " + result);
	}
	
}

// 回调接口
interface ICallBack {
	int fun(int a, int b, String message);
}

同步锁串行实现数据传递
public class ThreadDemo02 {
	public static void main(String[] args) {
		MyObject object = new MyObject();

		// 线程A与线程B 持有的是同一个对象:object
		ThreadA a = new ThreadA(object);
		ThreadB b = new ThreadB(object);
		ThreadC c = new ThreadC(object);
		
		a.start();
		b.start();
		c.start();
		
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
		System.out.println(object.getData());
	}
}

// 锁对象
class MyObject {
	
	private String data = "";

	public synchronized void methodA(String message) {
		System.out.println(message);
		data += message;
	}

	public synchronized void methodB(String message) {
		
		System.out.println(message);
		data += message;
	}

	public synchronized void methodC(String message) {
		System.out.println(message);
		data += message;
	}
	
	public void setData(String data) {
		this.data = data;
	}
	
	public String getData() {
		return data;
	}
}

class ThreadA extends Thread {

	private MyObject object;

	public ThreadA() {
		super();
	}

	public ThreadA(MyObject object) {
		super();
		this.object = object;
	}

	@Override
	public void run() {
		object.methodA("A");
	}
}

class ThreadB extends Thread {

	private MyObject object;

	public ThreadB() {
		super();
	}

	public ThreadB(MyObject object) {
		super();
		this.object = object;
	}

	@Override
	public void run() {
		object.methodB("B");
	}
}

class ThreadC extends Thread {

	private MyObject object;

	public ThreadC() {
	}

	public ThreadC(MyObject object) {
		this.object = object;
	}

	@Override
	public void run() {
		object.methodC("C");
	}
	
}
利用等待唤醒机制(生产者和消费者模型)
//消费者类
public class Consumer implements Runnable {
	
	private Toy toy;
	
	public Consumer(Toy toy) {
		this.toy = toy;
	}

	@Override
	public void run() {
		while(true) {
			synchronized (toy) {
				try {
					System.out.println(Thread.currentThread().getName()+"synchronized");
					Thread.sleep(100);
				} catch (InterruptedException e1) {
					
					e1.printStackTrace();
				}
                //判断是否有玩具
				if(!toy.isExist()) {
					try{
						System.out.println(Thread.currentThread().getName()+"wait()-->之前");
						Thread.sleep(100);
						//没有玩具就等待生产者生产	
                        //wait()的作用是让当前线程进入等待状态,同时,wait()也会让当前线程释放它所持有的锁
						toy.wait();
				
						Thread.sleep(100);
						System.out.println(Thread.currentThread().getName()+"wait()-->之后");
					 } catch (InterruptedException e) {
					
						e.printStackTrace();
					 }
				}
				//如果有就开始,消费
				int Lnum = toy.getNum();
				toy.setNum(--Lnum);
				System.out.println(Thread.currentThread().getName()+"这里还有:"+(++Lnum)+
						"--->卖了一个还剩:"+toy.getNum());
                if((toy.getNum())<= 0 ) {
                    //如果卖完了那么就设置exist为false
					toy.setExist(false);
                    //利用notify()唤醒则是唤醒当前对象上的等待线程
					toy.notify();
				}
			}
			
		}
		
	}
}



//生产者类
public class Producer implements Runnable {

	private Toy toy;
	
	public Producer(Toy toy) {
		this.toy = toy;
	}

	@Override
	public void run() {
		while(true) {
			synchronized (toy) {
				try {
					System.out.println(Thread.currentThread().getName()+"synchronized");
					Thread.sleep(100);
				} catch (InterruptedException e1) {
					e1.printStackTrace();
				}
                //判断是否有玩具
				if(toy.isExist()) {
					try {
							System.out.println(Thread.currentThread().getName()+"wait()-->之前");
							Thread.sleep(100);
						//有玩具就等待消费者消费
                        //让当前线程进入等待状态,同时程释放它所持有的锁
						toy.wait();
					
							Thread.sleep(100);
						System.out.println(Thread.currentThread().getName()+"wait()-->之后");
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
                //如果没有了就生产
				System.out.println(Thread.currentThread().getName()+"-->开始生产了");
				toy.setName("hahaw");
				toy.setNum(20);
				if(toy.getNum()>0) {
                    //生产好了就设置exist为true
					toy.setExist(true);
                    //利用notify()唤醒则是唤醒当前对象上的等待线程
					toy.notify();
					System.out.println(Thread.currentThread().getName()+"-->生成结束");
				}
			}
		
		}
		
	}
}



//玩具类
public class Toy {
	//玩具的名字
	private String name;
    //玩具的个数
	private Integer num;
    //是否还有玩具
	private boolean exist;
	public Toy() {
	}
	public Toy(String name, Integer num, boolean exist) {
		this.name = name;
		this.num = num;
		this.exist = exist;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Integer getNum() {
		return num;
	}
	public void setNum(Integer num) {
		this.num = num;
	}
	public boolean isExist() {
		return exist;
	}
	public void setExist(boolean exist) {
		this.exist = exist;
	}
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + (exist ? 1231 : 1237);
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		result = prime * result + ((num == null) ? 0 : num.hashCode());
		return result;
	}
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Toy other = (Toy) obj;
		if (exist != other.exist)
			return false;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		if (num == null) {
			if (other.num != null)
				return false;
		} else if (!num.equals(other.num))
			return false;
		return true;
	}
	@Override
	public String toString() {
		return "Toy [name=" + name + ", num=" + num + ", exist=" + exist + "]";
	}	
}


//测试类
public class TestClass {

	public static void main(String[] args) {
		Toy toy = new Toy();
		Producer p = new Producer(toy);
		Consumer c = new Consumer(toy);
		Thread t1 = new Thread(p,"生产者");
		Thread t2 = new Thread(c,"消费者");
		t1.start();
		t2.start();
	}

}

volatile关键字

保证变量在线程间可见,对volatile修饰的变量所有的写操作都能立即反应到其他线程中

synchronized和volatile的区别

1.volatile轻量级,只能修饰变量。synchronized重量级,还可修饰方法

2.volatile只能保证数据的可见性,不能用来同步,因为多个线程并发访问volatile修饰的变量不会阻塞。

3.synchronized不仅保证可见性,而且还保证原子性,因为,只有获得了锁的线程才能进入临界区,从而保证临界区中的所有语句都全部执行。多个线程争抢synchronized锁对象时,会出现阻塞。

private volatile boolean flag = true ;

本地线程

针对每一个线程都提供对应的副本数据,这样操作每次只操作自己副本数据,保证了线程的安全,同时也提高了效率,但是操作的不是同一份数据

public class ThreadLocalDemo {
	public static void main(String[] args) {
        //我们自己定义的
//		MyLocalThread<User> tl = new MyLocalThread<User>();
        //jdk自带的
		ThreadLocal<User> tl = new ThreadLocal<User>();
		tl.set(new User("小明", 18));
		
		new Thread(new Runnable() {
			
			@Override
			public void run() {
				User user = new User("小红", 25);
				tl.set(user);
				
				user.setName("嘿嘿");
				System.out.println(tl.get());
			}
		}).start();
		
		try {
			Thread.sleep(1000L);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		System.out.println(tl.get());
	}
}

class MyLocalThread<T> {
	private HashMap<Thread, T> hm;

	public MyLocalThread() {
		hm = new HashMap<>();
	}
	
	// 添加数据到map中
	public void set(T t) {
		hm.put(Thread.currentThread(), t);
	}
	
	// 通过线程对象获取数据
	public T get() {
		return hm.get(Thread.currentThread());
	}
	
}

class User {
	private String name;
	private int age;
	
	public User() {
		super();
	}
	
	public User(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	@Override
	public String toString() {
		return "User [name=" + name + ", age=" + age + "]";
	}
	
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值