Java--多线程Thread(实现,并发并行,同步死锁,单例,线程组池)

一、线程
   线程是程序执行的一条路径, 一个进程中可以包含多条线程
   多线程并发执行可以提高程序的效率, 可以同时完成多项工作

线程状态图

《Java--多线程Thread(实现,并发并行,同步死锁,单例,线程组池)》

二、多线程并行和并发的区别
  
1、并行就是两个任务同时运行,就是甲任务进行的同时,乙任务也在进行。(需要多核CPU)
   2、并发是指两个任务都请求运行,而处理器只能按受一个任务,就把这两个任务安排轮流进行,
   由于时间间隔较短,使人感觉两个任务都在运行。
   比如我跟两个网友聊天,左手操作一个电脑跟甲聊,同时右手用另一台电脑跟乙聊天,这就叫并行。
   如果用一台电脑我先给甲发个消息,然后立刻再给乙发消息,然后再跟甲聊,再跟乙聊。这就叫并发。

三、Java程序运行原理
      Java命令会启动java虚拟机,启动JVM,等于启动了一个应用程序,也就是启动了一个进程。
   该进程会自动启动一个 “主线程” ,然后主线程去调用某个类的 main 方法
      JVM启动至少启动了垃圾回收线程和主线程,所以是多线程的。

四、多线程实现的两种方式
1、继承Thread
    (1)定义类继承Thread
    (2)重写run方法
    (3)把新线程要做的事写在run方法中
    (4)创建线程对象
    (5)开启新线程, 内部会自动执行run方法
2、实现Runnable
    (1)定义类实现Runnable接口
    (2)实现run方法
    (3)把新线程要做的事写在run方法中
    (4)创建自定义的Runnable的子类对象
    (5)创建Thread对象, 传入Runnable
    (6)调用start()开启新线程, 内部会自动调用Runnable的run()方法
3、实现Runnable的原理
    (1)看Thread类的构造函数,传递了Runnable接口的引用
    (2)通过init()方法找到传递的target给成员变量的target赋值
    (3)查看run方法,发现run方法中有判断,如果target不为null就会调用Runnable
 接口子类对象的run方法
4、两种方式区别
  [1]查看源码的区别:
     (1)继承Thread : 由于子类重写了Thread类的run(), 当调用start()时, 直接找子类的run()方法
     (2)实现Runnable : 构造函数中传入了Runnable的引用, 成员变量记住了它, start()调用run()方法
   时内部判断成员变量Runnable的引用是否为空, 不为空编译时看的是Runnable的run(),运行时执行的
   是子类的run()方法
 [2]继承Thread
     好处是:可以直接使用Thread类中的方法,代码简单
     弊端是:如果已经有了父类,就不能用这种方法
 [3]实现Runnable接口
  好处是:即使自己定义的线程类有了父类也没关系,因为有了父类也可以实现接口,而且接口是可以多实现的
  弊端是:不能直接使用Thread中的方法需要先获取到线程对象后,才能得到Thread的方法,代码复杂

五、同步代码块
1、同步情况
 当多线程并发, 有多段代码同时执行时, 我们希望某一段代码执行的过程中CPU不要切换到其他线程工作. 这时就需要同步.
 如果两段代码是同步的, 那么同一时间只能执行一段, 在一段代码没执行结束之前, 不会执行另外一段代码.
2、同步代码块
 使用synchronized关键字加上一个锁对象来定义一段代码, 这就叫同步代码块
 多个同步代码块如果使用相同的锁对象, 那么他们就是同步的
3、非静态同步函数的锁是:this
      静态的同步函数的锁是:字节码对象
4、Vector是线程安全的,ArrayList是线程不安全的
   StringBuffer是线程安全的,StringBuilder是线程不安全的
   Hashtable是线程安全的,HashMap是线程不安全的

public class Thread1 {
	public static void main(String[] args) {
//		JVMStart();//Java程序运行原理和JVM的启动
//		threadStart1();//开启线程方式1
//		threadStart2();//开启线程方式2
//		anonymousThread();//匿名内部类实现线程的两种方式
//		daemonThread();
//		joinThread();
		synchronizedThread();
	}

	public static void synchronizedThread() {
		final Printer p = new Printer();
		new Thread(){
			public void run(){
				for(int i = 0;i < 100;i++){   
					p.print1();
				}
			}
		}.start();
		new Thread(){
			public void run(){
				for(int i = 0;i < 100;i++){   
					p.print2();
				}
			}
		}.start();
	}

	public static void joinThread() {
		final Thread t1 = new Thread(){
			public void run(){
				for(int i = 0;i < 10;i++){   
					System.out.println(this.getName() + "..." + "aaaaaaaaaa");
				}
			}
		};
		//匿名内部类再使用它所在方法中的局部变量时,必须使用final修饰
		Thread t2 = new Thread(){
			public void run(){
				for(int i = 0;i < 10;i++){ 
//					if(i == 2){
//						try {
//							t1.join();
//						} catch (InterruptedException e) {
//							e.printStackTrace();
//						}
//					}
					System.out.println(this.getName() + "..." + "bbbb");
				}
			}
		};
		t1.setPriority(Thread.MIN_PRIORITY);//设置线程优先级,最大10,最小1,默认5
		t2.setPriority(Thread.MAX_PRIORITY);
		t1.start();
		t2.start();
	}

	public static void daemonThread() {
		/*守护线程
		  setDaemon(), 设置一个线程为守护线程, 该线程不会单独执行, 
		 当其他非守护线程都执行结束后, 自动退出
		 */
		Thread t1 = new Thread(){
			public void run(){
				for(int i = 0;i < 2;i++){   
					System.out.println(this.getName() + "..." + "aaaaaaaaaa");
				}
			}
		};
		Thread t2 = new Thread(){
			public void run(){
				for(int i = 0;i <= 50;i++){   
					System.out.println(this.getName() + "..." + "bbbb");
				}
			}
		};
		t2.setDaemon(true);
		t1.start();
		t2.start();
	}

	public static void anonymousThread() {
		//1、继承Thread类
		new Thread("线程名字"){
			public void run(){
				this.setName("哈哈");
				System.out.println(this.getName() + "..." + "aaaaaaaa");
//				for(int i = 0;i <= 1000;i++){   
//					System.out.println("aaaaaaaa");
//				}
			}
		}.start();
		
		//2、实现Runnable接口
		new Thread(new Runnable() {
			@Override
			public void run() {
				System.out.println(Thread.currentThread().getName() + "..." + "bbbb");
//				System.out.println("bbbb");
//				for(int i = 0;i <= 1000;i++){   
//					System.out.println("bbbb");
//				}
			}
		}).start();
		
		//currentThread()获取当前线程对象
		System.out.println(Thread.currentThread().getName() + "..." + "cccc");
//		for(int i = 0;i <= 1000;i++){   
//			System.out.println("cc");
//		}
	}

	public static void threadStart2() {
		MyRunnabel mr = new MyRunnabel();  //4、创建Runnable子类
		Thread t = new Thread(mr);		   //5、将其当做参数传递给Thread的构造方法
		t.start();						   //6、开启多线程
		
		for(int i = 0;i <= 1000;i++){
			System.out.println("bbbb");
		}
	}

	public static void threadStart1() {
		MyThread mt = new MyThread();  //4、创建继承Thread的子线程
		mt.start();					   //5、开启子线程
		
		for(int i = 0;i <= 1000;i++){
			System.out.println("bbbb");
		}
	}

	public static void JVMStart() {
		for(int i = 0;i < 1000000;i++){
			new Demo();
		}
		for(int i = 0;i < 10000;i++){
			System.out.println("我是主程序的执行代码");
		}
	}
}

class MyRunnabel implements Runnable{   //1、定义一个类实现Runnable接口
	@Override
	public void run() {					//2、重写run方法
		for(int i = 0;i <= 1000;i++){   //3、将要执行的代码写在run方法中
			System.out.println("aaaaaaaa");
		}
	}
}

class MyThread extends Thread{    //1、继承Thread
	public void run(){            //2、重写run方法
		for(int i = 0;i <= 1000;i++){   //3、将要执行的代码写在run方法中
			System.out.println("aaaaaaaa");
		}
	}
}

class Printer{
	Lock l = new Lock();
	public void print1(){    //同步代码块,锁机制,锁可以是任意对象
		synchronized(l){
			System.out.print("1");
			System.out.print("2");
			System.out.print("3");
			System.out.print("4");
			System.out.print("5");
			System.out.print("6");
			System.out.print("\r\n");
		}
	}
	
	public void print2(){    //锁对象不能使用匿名对象,因为匿名对象不是同一个类
		synchronized(l){
			System.out.print("a");
			System.out.print("b");
			System.out.print("c");
			System.out.print("d");
			System.out.print("e");
			System.out.print("f");
			System.out.print("\r\n");
		}
	}
}

class Lock{}

class Demo{
	@Override
	public void finalize(){
		System.out.println("清扫垃圾");;
	}
}

六、单例设计模式:保证类在内存中只有一个对象

饿汉式和懒汉式区别:

[1]饿汉式是空间换时间,懒汉式是时间换空间;目前硬盘空间可扩充,但是时间不好压缩,

因此开发更倾向于饿汉式

[2]在多线程中,饿汉式只会创建一个对象,但是懒汉式有可能会创建多个对象

七、线程间的通信

1、什么时候需要通信

多个线程并发执行时, 在默认情况下CPU是随机切换线程的

如果我们希望他们有规律的执行, 就可以使用通信, 例如每个线程执行一次打印

2、两个线程之间怎么通信

如果希望线程等待, 就调用wait()

如果希望唤醒等待的线程, 就调用notify();

这两个方法必须在同步代码中执行, 并且使用同步锁对象来调用

3、多个线程通信

notify()方法是随机唤醒一个线程

notifyAll()方法是唤醒所有线程

JDK5之前无法唤醒指定的一个线程

如果多个线程之间通信, 需要使用notifyAll()通知所有线程, 用while来反复判断条件

4、同步代码块中,使用哪个对象锁,就用哪个对象调用wait方法

5、wait和notify方法定义在Object类中

     锁对象可以是任意对象,Object是所有类的基类,所以wait方法和notify方法需要定义在Object中

6、sleep和wait区别

     (1)sleep方法必须传入参数,参数是时间,时间到了自然醒来

     wait方法可以传入参数也可以不传参数,传入参数就是在参数的时间结束后等待,不传参就直接等待

     (2)sleep方法在同步方法或者同步代码块中,不释放锁,抱着锁一起睡

     wait方法在同步方法或者同步代码块中,释放锁

八、JDK1.5的新特性互斥锁

1、同步:使用ReentrantLock类的lock()和unlock()方法进行同步

2、通信

使用ReentrantLock类的newCondition()方法可以获取Condition对象

需要等待的时候使用Condition的await()方法, 唤醒的时候用signal()方法

不同的线程使用不同的Condition, 这样就能区分唤醒的时候找哪个线程了

九、线程组

1、线程组概述

Java中使用ThreadGroup来表示线程组,它可以对一批线程进行分类管理,Java允许程序直接对线程组进行控制。

默认情况下,所有的线程都属于主线程组。

  public final ThreadGroup getThreadGroup()//通过线程对象获取他所属于的组

  public final String getName()//通过线程组对象获取他组的名字

也可以给线程设置分组

  [1]ThreadGroup(String name) 创建线程组对象并给其赋值名字

  [2]创建线程对象

  [3]Thread(ThreadGroup?group, Runnable?target, String?name) 

  [4]设置整组的优先级或者守护线程

2、线程五种状态:新建,就绪,运行,阻塞,死亡

十、线程池

1、线程池

程序启动一个新线程成本是比较高的,因为它涉及到要与操作系统进行交互。而使用线程池可以很好的提高性能,

尤其是当程序中要创建大量生存期很短的线程时,更应该考虑使用线程池。线程池里的每一个线程代码结束后,并不会死亡,

而是再次回到线程池中成为空闲状态,等待下一个对象来使用。在JDK5之前,我们必须手动实现自己的线程池,从JDK5开始,

Java内置支持线程池

2、内置线程池的使用概述

JDK5新增了一个Executors工厂类来产生线程池,有如下几个方法

public static ExecutorService newFixedThreadPool(int nThreads)

public static ExecutorService newSingleThreadExecutor()

这些方法的返回值是ExecutorService对象,该对象表示一个线程池,可以执行Runnable对象或者Callable对象代表的线程。它提供了如下方法

Future<?> submit(Runnable task)

<T> Future<T> submit(Callable<T> task)

3、使用步骤:

创建线程池对象

创建Runnable实例

提交Runnable实例

关闭线程池

import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/*
 * 一、单例设计模式:保证类在内存中只有一个对象
	饿汉式和懒汉式区别:
	  [1]饿汉式是空间换时间,懒汉式是时间换空间;目前硬盘空间可扩充,但是时间不好压缩,
	  因此开发更倾向于饿汉式
	  [2]在多线程中,饿汉式只会创建一个对象,但是懒汉式有可能会创建多个对象
   二、线程间的通信
   1、什么时候需要通信
		多个线程并发执行时, 在默认情况下CPU是随机切换线程的
		如果我们希望他们有规律的执行, 就可以使用通信, 例如每个线程执行一次打印
   2、两个线程之间怎么通信
		如果希望线程等待, 就调用wait()
		如果希望唤醒等待的线程, 就调用notify();
		这两个方法必须在同步代码中执行, 并且使用同步锁对象来调用
   3、多个线程通信
		notify()方法是随机唤醒一个线程
		notifyAll()方法是唤醒所有线程
		JDK5之前无法唤醒指定的一个线程
		如果多个线程之间通信, 需要使用notifyAll()通知所有线程, 用while来反复判断条件
   4、同步代码块中,使用哪个对象锁,就用哪个对象调用wait方法
   5、wait和notify方法定义在Object类中
     锁对象可以是任意对象,Object是所有类的基类,所以wait方法和notify方法需要定义在Object中
   6、sleep和wait区别
     (1)sleep方法必须传入参数,参数是时间,时间到了自然醒来
     wait方法可以传入参数也可以不传参数,传入参数就是在参数的时间结束后等待,不传参就直接等待
     (2)sleep方法在同步方法或者同步代码块中,不释放锁,抱着锁一起睡
     wait方法在同步方法或者同步代码块中,释放锁
   三、JDK1.5的新特性互斥锁
   1、同步:使用ReentrantLock类的lock()和unlock()方法进行同步
   2、通信
		使用ReentrantLock类的newCondition()方法可以获取Condition对象
		需要等待的时候使用Condition的await()方法, 唤醒的时候用signal()方法
		不同的线程使用不同的Condition, 这样就能区分唤醒的时候找哪个线程了
    四、线程组
    1、线程组概述
	  Java中使用ThreadGroup来表示线程组,它可以对一批线程进行分类管理,Java允许程序直接对线程组进行控制。
	  默认情况下,所有的线程都属于主线程组。
		  public final ThreadGroup getThreadGroup()//通过线程对象获取他所属于的组
		  public final String getName()//通过线程组对象获取他组的名字
	  也可以给线程设置分组
		  [1]ThreadGroup(String name) 创建线程组对象并给其赋值名字
		  [2]创建线程对象
		  [3]Thread(ThreadGroup?group, Runnable?target, String?name) 
		  [4]设置整组的优先级或者守护线程
	2、线程五种状态:新建,就绪,运行,阻塞,死亡
	五、线程池
	1、线程池
		程序启动一个新线程成本是比较高的,因为它涉及到要与操作系统进行交互。而使用线程池可以很好的提高性能,
		尤其是当程序中要创建大量生存期很短的线程时,更应该考虑使用线程池。线程池里的每一个线程代码结束后,并不会死亡,
		而是再次回到线程池中成为空闲状态,等待下一个对象来使用。在JDK5之前,我们必须手动实现自己的线程池,从JDK5开始,
		Java内置支持线程池
	2、内置线程池的使用概述
	   JDK5新增了一个Executors工厂类来产生线程池,有如下几个方法
			public static ExecutorService newFixedThreadPool(int nThreads)
			public static ExecutorService newSingleThreadExecutor()
			这些方法的返回值是ExecutorService对象,该对象表示一个线程池,可以执行Runnable对象或者Callable对象代表的线程。它提供了如下方法
			Future<?> submit(Runnable task)
			<T> Future<T> submit(Callable<T> task)
	3、使用步骤:
		创建线程池对象
		创建Runnable实例
		提交Runnable实例
		关闭线程池
 * */
public class SingletonPattern {
	public static void main(String[] args) throws InterruptedException, ExecutionException {
//		timer();//Timer类
//		notifyThread();//等待唤醒线程
//		threadGroup();
//		threadGroup1();
//		threadPool();
		callable();
	}

	public static void callable() throws InterruptedException, ExecutionException {
		ExecutorService pool = Executors.newFixedThreadPool(2);
		Future<Integer> f1 = pool.submit(new MyCallable(100));
		Future<Integer> f2 = pool.submit(new MyCallable(50));
		System.out.println(f1.get());
		System.out.println(f2.get());
	}

	public static void threadPool() {
		ExecutorService pool = Executors.newFixedThreadPool(2);
		pool.submit(new MyRunnable());
		pool.submit(new MyRunnable());  //将线程放进线程池
		
		pool.shutdown();                //关闭线程池
	}

	public static void threadGroup1() {
		ThreadGroup tg = new ThreadGroup("新线程组");
		MyRunnable mr = new MyRunnable();
		
		Thread t1 = new Thread(tg, mr, "编号1");
		Thread t2 = new Thread(tg, mr, "编号2");
		System.out.println(t1.getThreadGroup().getName());
		System.out.println(t2.getThreadGroup().getName());
		
		tg.setDaemon(true);
	}

	public static void threadGroup() {
		MyRunnable mr = new MyRunnable();
		Thread t1 = new Thread(mr, "编号1");
		Thread t2 = new Thread(mr, "编号2");
		
		ThreadGroup tg1 = t1.getThreadGroup();
		ThreadGroup tg2 = t2.getThreadGroup();
		System.out.println(tg1.getName());
		System.out.println(tg2.getName());
	}

	public static void notifyThread() {
		Printer p = new Printer();
		new Thread(){
			public void run(){
				while(true){
					try {
						p.print1();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		}.start();
		new Thread(){
			public void run(){
				while(true){
					try {
						p.print2();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		}.start();
		new Thread(){
			public void run(){
				while(true){
					try {
						p.print3();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		}.start();
	}

	public static void timer() throws InterruptedException {
		Timer t = new Timer();
		t.schedule(new MyTimerTask(), new Date(117,2,13,10,55,00));
		while (true){
			Thread.sleep(1000);
			System.out.println(new Date());
		}
	}
}

//饿汉式(上来就先创建对象),开发更倾向于使用这种
class Singleton{
	//1、私有构造方法,其他类不能访问该构造方法了
	private Singleton(){}
	//2、创建本类对象
	private static Singleton s = new Singleton();
	//3、对外提供公共的访问方法
	public static Singleton getInstance(){
		return s;
	}
}

/*懒汉式(先声明对象)--单例的延迟加载模式
class Singleton{
	//1、私有构造方法,其他类不能访问该构造方法了
	private Singleton(){}
	//2、先声明对象
	private static Singleton s;
	//3、对外提供公共的访问方法
	public static Singleton getInstance(){
		if (s == null){
			/*如果是多线程,那么多线程抢占执行权限,有可能会多次创建对象,和单例设计模式中
			保证类在内存中只有一个对象思想背道而驰
			s = new Singleton();
		}
		return s;
	}
}*/

/*另一种格式
class Singleton{
	//1、私有构造方法,其他类不能访问该构造方法了
	private Singleton(){}
	//2、使用final修饰不能修改
	private static final Singleton s = new Singleton();
}*/

class MyTimerTask extends TimerTask{

	@Override
	public void run() {
		System.out.println("起床上班了");
	}
}

class Printer{
	private int flag = 1;
	private ReentrantLock r = new ReentrantLock();
	private Condition c1 = r.newCondition();
	private Condition c2 = r.newCondition();
	private Condition c3 = r.newCondition();
	public void print1() throws InterruptedException{    //同步代码块,锁机制,锁可以是任意对象
//		synchronized(this){
		r.lock();
			if(flag != 1){
//				this.wait();
				c1.await();
			}
			System.out.print("1");
			System.out.print("2");
			System.out.print("3");
			System.out.print("4");
			System.out.print("5");
			System.out.print("6");
			System.out.print("\r\n");
			flag = 2;
//			this.notify();
//			this.notifyAll();
			c2.signal();
//		}
		r.unlock();
	}
	
	public void print2() throws InterruptedException{    
//		synchronized(this){
		r.lock();
			if(flag != 2){
//				this.wait();
				c2.await();
			}
			System.out.print("a");
			System.out.print("b");
			System.out.print("c");
			System.out.print("d");
			System.out.print("e");
			System.out.print("f");
			System.out.print("\r\n");
			flag = 3;
//			this.notify();
//			this.notifyAll();
			c3.signal();
//		}
		r.unlock();
	}
	
	public void print3() throws InterruptedException{    //同步代码块,锁机制,锁可以是任意对象
//		synchronized(this){
		r.lock();
			if(flag != 3){
//				this.wait();
				c3.await();
			}
			System.out.print("A");
			System.out.print("B");
			System.out.print("C");
			System.out.print("\r\n");
			flag = 1;
//			this.notify();
//			this.notifyAll();
			c1.signal();
//		}
		r.unlock();
	}
}

class MyRunnable implements Runnable{
	@Override
	public void run() {
		for(int i = 0;i < 1000;i++){
			System.out.println(Thread.currentThread().getName() + "..." + i);
		}
	}
}

class MyCallable implements Callable<Integer>{
	private int num;
	public MyCallable(int num){
		this.num = num;
	}
	@Override
	public Integer call() throws Exception {
		int sum = 0;
		for(int i = 0;i <= num;i++){
			sum = sum + i;
		}
		return sum;
	}
}
    原文作者:java锁
    原文地址: https://blog.csdn.net/MinggeQingchun/article/details/61617807
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞