当前位置:首页 > Java技术 > java中的多线程Thread十九个实例带你轻松学会

java中的多线程Thread十九个实例带你轻松学会

2022年11月09日 20:14:45Java技术6

@

1.什么是进程?什么是线程?
	进程是一个应用程序/软件
	线程是一个进程中的执行单元/执行场景
	一个进程可以启动多个线程
	线程之间内存独立不共享
	进程之间堆内存和方法区内存共享,栈内存独立
2.对于单核的CPU来说,实际上不存在多线程并发,而是多个线程切换的很快,让人有种并发的错觉
3.java语言中实现线程的方式:
	1.编写一个类,直接继承java.lang.Thread,重写run方法
	2.※编写一个类,实现java.lang.Runnable接口(尽量使用面向接口编程)
4.线程的生命周期:
	新建状态,就绪状态,运行状态,阻塞状态,死亡状态
5.关于线程的调度(了解)
	常见的线程调度有哪些?
		抢占式调度模型:线程优先度越高越容易抢占(java)
		均分式调度模型:每个线程占用CPU时间片时间长度相同
	java中提供了哪些方法和线程调度有关系?
		实例方法:
			void setPriority(int newPriority)设置线程的优先级
			int getPriority()获取线程优先级
			默认是5(1-10)
		静态方法:
			static void yield()让位方法
			暂停当前正在执行的线程对象,并执行其他线程
			yield()方法不是阻塞方法。让当前线程让位,让给其他线程使用
			yield()方法的执行会让当前线程从“运行状态”回到“就绪状态”
			注意:在回到就绪状态的时候,有可能还会再次抢到
		实例方法:
			void join()
			合并线程
			class MyThread1 extends Thread{
				public void doSome(){
					MyThread2 t = new Thread();
					t.join();//当前线程进入阻塞,t线程执行,直到t线程结束,当前线程才可以执行
				}
			}
			class MyThread2 extends Thread{
			
			}
6.※关于多线程并发环境下,数据的安全问题
	什么时候存在安全问题呢?
		条件1:多线程并发
		条件2:有共享数据
		条件3:共享数据有修改的行为
	怎么解决线程安全问题呢?
		用排队执行解决线程安全问题
		这种机制被称为:线程同步机制
		线程同步会降低效率,但提高了数据的安全性,只有数据足够安全的基础上,才考虑提高程序的效率
	线程同步:
		异步编程模型:
			线程t1和线程t2,分别执行(多线程并发)(效率高)
		同步编程模型:
			线程t1和线程t2在执行时发生了等待关系(排队执行)(效率低)
			线程同步的语法是:
				1.同步代码块:
					synchronized (actno) {
					}
					参数必须是多线程共享的数据才能达到多线程排队
				2.在实例方法上用synchronized
					当synchronized出现在实例方法上一定锁的是this
					缺点:表示整个方法体都需要同步,可能导致效率变低
					优点:代码简洁
				3.在静态方法上用synchronized
					表示找类锁,保证静态变量的安全
					类锁永远只有1把,对象锁可以有N把
	java中的三大变量:
		实例变量:堆中
		静态变量:方法区中
		局部变量:栈中
		以上三大变量中:局部变量永远都不会存在线程安全问题,因为它不共享
	java中的集合:
		ArrayList是非线程安全的
		Vector是线程安全的
		HashMap、HashSet是非线程安全的
		Hashtable是线程安全的
	如何解决线程安全问题?
		1.尽量使用局部变量代替实例变量和静态变量
		2.如果必须是实例对象,那么可以考虑创建多个对象,这样实例变量的内存就不共享了(一个线程对应一个对象)
		3.如果不能使用局部变量,对象也不能创建多个,这时采用synchronized线程同步机制了
7.线程的其他内容:
	1.守护线程
		java语言中线程分为两大类:
			1.用户线程
			2.守护线程(后台线程)
				其中具有代表性的就是:垃圾回收线程(守护线程)
		守护线程的特点:
			死循环,所有用户线程结束,守护线程自动结束
	2.定时器
		作用:间隔特定时间执行特定程序
		实现:
			1.sleep睡眠,少用
			2.java.util.Timer,少用
			3.spring框架提供的SpringTask框架(底层还是Timer)
	3.实现线程的三种方式:实现Callable接口(JDK 8)
		这种方式实现的线程可以获取线程的返回值
		之前的两种方式无法获取
		优点:获取程序执行结果
		缺点:效率比较低,在拿到返回结果之前,当前程序受阻塞
	3.关于Object类中的wait和notify方法(生产者和消费者模式)(synchronized基础上)
		1.任何对象都有,Object类自带的
		2.wait()方法的作用:
			Object o = new Object();
			o.wait();
			表示:让正在o对象上活动的线程t进入等待状态,释放掉t线程之前占有的对象的锁,直到被唤醒为止
		3.notify方法的作用:
			Object o = new Object();
			o.notify();
			表示:唤醒正在o对象上等待的线程,没有释放o对象占有的锁
			o.notifyAll();
			表示:唤醒所有正在o对象上等待的线程

一图流:
java中的多线程Thread十九个实例带你轻松学会 _ JavaClub全栈架构师技术笔记

实例一:判断程序除垃圾回收外,有几个线程

package thread;
/*
	除垃圾回收外,有几个线程
		1个
 */
public class ThreadTest01 {

	public static void main(String[] args) {
		System.out.println("main begin");
		m1();
		System.out.println("main over");
	}

	private static void m1() {
		// TODO Auto-generated method stub
		System.out.println("m1 begin");
		m2();
		System.out.println("m1 over");
	}

	private static void m2() {
		// TODO Auto-generated method stub
		System.out.println("m2 begin");
		m3();
		System.out.println("m2 over");
	}

	private static void m3() {
		// TODO Auto-generated method stub
		System.out.println("m3 begin");
		System.out.println("m3 over");
		
	}

}

实例二:实现线程的第一种方式继承java.lang.Thread类

package thread;


/*
	java语言中实现线程的第一种方式:
		1.编写一个类,直接继承java.lang.Thread,重写run方法
		2.创建线程对象
		3.启动线程
 */
public class ThreadTest02 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		//新建一个分支线程对象
		MyThread myThread = new MyThread();
		//启动线程
		//start方法的作用是:启动一个分支线程,在JVM中开辟一个新的栈空间,开辟完成,方法结束
		//启动成功的线程会自动调用run方法,并且run方法在分支栈的底部(压栈)
		myThread.start();
		//此处代码还是在主线程中
		for(int i = 0;i<1000;i++) {
			System.out.println("主线程--->"+i);
		}
	}
	
}

class MyThread extends Thread{
	public void run() {
		//编写程序,此程序运行在分支线程中(分支栈)。
		for(int i = 0;i<1000;i++) {
			System.out.println("分支线程--->" + i);
		}
	}
}

实例三:实现线程的第二种方式实现java.lang.Runnable接口

package thread;
/*
	java语言中实现线程的第二种方式:
		1.编写一个类,实现java.lang.Runnable接口
		2.创建线程对象
		3.启动线程
 */
public class ThreadTest03 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		//创建一个可运行的对象
		//MyRunnable r = new MyRunnable();
		//将可运行的对象封装成一个线程对象
		//Thread t = new Thread(r);
		//合并
		Thread t = new Thread(new MyRunnable());
		t.start();
		for(int i = 0;i<1000;i++) {
			System.out.println("主线程--->"+i);
		}
	}

}

//这不是一个线程类
class MyRunnable implements Runnable{
	public void run() {
		for(int i = 0;i<1000;i++) {
			System.out.println("分支线程--->" + i);
		}
	}
}

实例四:采用匿名内部类的方式实现线程

package thread;
/*
	匿名内部类
 */
public class ThreadTest04 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		//
		Thread t = new Thread(new Runnable() {
			public void run() {
				for(int i = 0;i<1000;i++) {
					System.out.println("分支线程--->" + i);
				}
			}
		});
		//启动线程
		t.start();
		for(int i = 0;i<1000;i++) {
			System.out.println("主线程--->"+i);
		}
	}

}

实例五:获取当前线程对象及相关操作

package thread;
/*
	1.怎么获取当前线程对象
		static Thread currentThread();
	2.获取线程对象的名字
		String getName();
	3.修改线程对象的名字
		void setName("");
	4.当线程没有设置名字时
		Thread-0
		Thread-1
		……
 */
public class ThreadTest05 {

	public static void main(String[] args) {
		Thread current = Thread.currentThread();
		//代码出现在main方法当中,所以获取的就是main线程对象
		System.out.println(current.getName());
		
		MyThread2 r = new MyThread2();
		r.setName("SYH");
		String rName = r.getName();//默认为Thread-0
		//System.out.println(rName);
		MyThread2 r2 = new MyThread2();
		r2.setName("LXY");
		//System.out.println(r2.getName());//Thread-1
		r.start();
		r2.start();
	}

}
class MyThread2 extends Thread{
	public void run() {
		Thread current = Thread.currentThread();
		//代码出现在分支方法当中,所以获取的就是分支线程对象
		System.out.println(current.getName());
		for(int i = 0;i<1000;i++) {
			//System.out.println("分支线程--->"+i);
		}
	}
}

实例六:关于线程的sleep方法

package thread;
/*
	关于线程的sleep方法
		static void sleep(long millis)
		1.静态方法
		2.参数是毫秒
		3.作用:让当前线程进入休眠状态,进入“阻塞状态”,放弃占有CPU时间片,让给其他线程
		4.可以间隔特定时间执行代码
 */
public class ThreadTest06 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		try {
			Thread.sleep(1000*5);//睡眠5秒
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("Hello World");
		for(int i = 0;i<10;i++) {
			System.out.println(Thread.currentThread().getName()+"-->"+i);
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

}

实例七:sleep相关面试题

package thread;
/*
	面试题
		对象使用sleep
 */
public class ThreadTest07 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Thread t = new MyThread3();
		t.setName("t");
		t.start();
		try {
			//这行代码会让线程t进去休眠吗?
			t.sleep(1000);//在执行时自动转换为Thread.sleep();
			//出现在main方法当中,main线程睡眠
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("helloWord");
	}

}
class MyThread3 extends Thread{
	public void run() {
		//编写程序,此程序运行在分支线程中(分支栈)。
		for(int i = 0;i<1000;i++) {
			System.out.println("分支线程--->" + i);
		}
	}
}

实例八:如何唤醒睡眠(sleep)中的线程

package thread;
/*
	sleep睡眠太久了,如果希望中途醒来,应该怎么做(如何唤醒睡眠的线程)
 */
public class ThreadTest08 extends Thread{

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Thread t = new Thread(new MyRunnable2());
		t.setName("tt");
		t.start();
		//希望5秒后醒来
		try {
			Thread.sleep(1000*5);//给主线程模拟5s的用时
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		t.interrupt();//中断睡眠,依靠了java的异常处理机制
	}

}
class MyRunnable2 implements Runnable{
	//run()方法在父类中没有抛出任何异常,所以run()中的一场只能try-catch
	public void run() {
		System.out.println(Thread.currentThread().getName()+"-->begin");
		try {
			Thread.sleep(1000*60*60);
			//为什么这里只能try-catch,因为子类不能比父类抛出更宽泛的异常
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println(Thread.currentThread().getName()+"-->over");
	}
}

实例九:强制终止一个线程

package thread;
/*
	强制终止一个线程
 */
public class ThreadTest09 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Thread t = new Thread(new MyRunnable3());
		t.setName("ttt");
		t.start();
		try {
			Thread.sleep(1000*5);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		//终止t线程
		//缺点:直接杀死线程,容易丢失数据
		t.stop();//已过时(不建议使用)
	}

}
class MyRunnable3 implements Runnable{
	public void run() {
		for(int i = 0;i<10;i++) {
			System.out.println(Thread.currentThread().getName()+"-->"+i);
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}

实例十:合理的终止一个线程

package thread;
/*
	合理的终止一个线程
 */
public class ThreadTest10 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		MyRunnable4 r =new MyRunnable4();
		Thread t = new Thread(r);
		t.setName("ttt");
		t.start();
		//模拟工作5秒
		try {
			Thread.sleep(1000*5);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		//终止线程
		r.run = false;//什么时候想要终止线程,什么时候设置为false即可
	}

}
class MyRunnable4 implements Runnable{
	
	//一个布尔标记
	boolean run = true;
	
	public void run() {
		for(int i = 0;i<10;i++) {
			if(run) {
				System.out.println(Thread.currentThread().getName()+"-->"+i);
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}else {
				return;
			}
		}
	}
}

实例十一:关于线程优先级

package thread;
//关于线程优先级
public class ThreadTest11 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		System.out.println("最高优先级"+Thread.MAX_PRIORITY);//10
		System.out.println("最低优先级"+Thread.MIN_PRIORITY);//1
		System.out.println("默认优先级"+Thread.NORM_PRIORITY);//5
		
		//获取当前线程对象的优先级
		Thread currentThread = Thread.currentThread();
		currentThread.setPriority(1);
		System.out.println(currentThread.getName()+"的优先级是"+currentThread.getPriority());//5
		Thread t = new Thread(new MyRunnable5());
		t.setName("tt");
		t.setPriority(10);
		t.start();
		for(int i = 0;i<1000;i++) {
			System.out.println("主线程-->"+i);
		}
	}

}
class MyRunnable5 implements Runnable{
	public void run() {
		System.out.println(Thread.currentThread().getName()+"的优先级是"+Thread.currentThread().getPriority());
		for(int i = 0;i<1000;i++) {
			System.out.println("分支线程-->"+i);
		}
	}
}

实例十二:线程的让位方法

package thread;
/*
	让位,当前线程暂停,回到就绪状态,让给其他线程
	静态方法:Thread.yield();
 */
public class ThreadTest12 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Thread t = new Thread(new MyRunnable6());
		t.setName("ttt");
		t.start();
		for(int i = 0;i<1000;i++) {
			System.out.println(Thread.currentThread().getName()+"-->"+i);
		}
	}

}
class MyRunnable6 implements Runnable{
	public void run() {
		for(int i = 0;i<1000;i++) {
			if(i % 100 == 0) {
				Thread.yield();//每一百个让位一次
			}
			System.out.println(Thread.currentThread().getName()+"-->"+i);
		}
		
	}
}

实例十三:线程合并

package thread;
//线程合并
public class ThreadTest13 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		System.out.println("main begin");
		Thread t = new Thread(new MyRunnable7());
		t.setName("t");
		t.start();
		try {
			t.join();//t合并到当前线程中,当前线程受阻塞,t线程执行直到结束
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("main over");
	}

}
class MyRunnable7 implements Runnable{

	@Override
	public void run() {
		// TODO Auto-generated method stub
		for(int i = 0;i<1000;i++) {
			System.out.println(Thread.currentThread().getName()+"-->"+i);
		}
	}
	
}

实例十四:守护线程

package thread;
/*
	守护线程
 */
public class ThreadTest14 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Thread t = new BakDataThread();
		t.setName("备份数据的线程");
		t.setDaemon(true);
		t.start();
		//主线程(用户线程)
		for(int i = 0;i<10;i++) {
			System.out.println(Thread.currentThread().getName()+"-->"+i);
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

}
class BakDataThread extends Thread{
	public void run() {
		int i =0;
		//即使是死循环也会自动退出
		while(true) {
			System.out.println(Thread.currentThread().getName()+"-->"+(++i));
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}

实例十五:实现线程的第三种方式:实现Callable接口

package thread;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;//JUC包下的,属于java的并发包,老JDK中没有这个包

/*
	实现线程的第三种方式:实现Callable接口
		优点:获取程序执行结果
		缺点:效率比较低
 */
public class ThreadTest15 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		//1.创建一个未来任务类
		FutureTask task = new FutureTask(new Callable() {//参数非常重要,需要给一个Callable接口实现类对象
			public Object call() throws Exception{//相当于run方法,不过有返回值
				System.out.println("call method begin");
				Thread.sleep(1000);
				System.out.println("call method over");
				int a = 100;
				int b = 200;
				return a+b;//自动装箱 
			}
		});
		Thread t = new Thread(task);
		t.start();
		//在主线程中,怎么获取t线程的返回结果
		Object obj = null;
		try {
			obj = task.get();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ExecutionException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println(obj);
		//后边的代码想要执行,必须等get方法结束
		//而想要让get方法结束必须等t线程结束拿到返回值
		//
		
	}

}

实例十六:线程同步相关面试题

exam1

package exam;
//面试题:doOther方法执行的时候需要等待doSome方法的结束吗?
	//不需要,因为doOther方法没有使用synchronized修饰
public class Exam01 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		MyClass mc = new MyClass();
		Thread t1 = new MyThread(mc);
		Thread t2 = new MyThread(mc);
		t1.setName("t1");
		t2.setName("t2");
		t1.start();
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}//保证t1先执行
		t2.start();
	}

}
class MyThread extends Thread{
	private MyClass mc;
	public MyThread(MyClass mc) {
		this.mc = mc;
	}
	public void run() {
		if(Thread.currentThread().getName().contentEquals("t1")) {
			mc.doSome();
		}
		if(Thread.currentThread().getName().contentEquals("t2")) {
			mc.doOther();
		}
	}
}
class MyClass{
	public synchronized void doSome() {
		System.out.println("doSome begin");
		try {
			Thread.sleep(1000*10);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("doSome over");
	}
	public void doOther() {
		System.out.println("doOther Begin");
		System.out.println("doOther Over");
	}
}

exam2

package exam2;
//面试题:doOther方法执行的时候需要等待doSome方法的结束吗?
	//需要
public class Exam01 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		MyClass mc = new MyClass();
		Thread t1 = new MyThread(mc);
		Thread t2 = new MyThread(mc);
		t1.setName("t1");
		t2.setName("t2");
		t1.start();
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}//保证t1先执行
		t2.start();
	}

}
class MyThread extends Thread{
	private MyClass mc;
	public MyThread(MyClass mc) {
		this.mc = mc;
	}
	public void run() {
		if(Thread.currentThread().getName().contentEquals("t1")) {
			mc.doSome();
		}
		if(Thread.currentThread().getName().contentEquals("t2")) {
			mc.doOther();
		}
	}
}
class MyClass{
	public synchronized void doSome() {
		System.out.println("doSome begin");
		try {
			Thread.sleep(1000*10);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("doSome over");
	}
	public synchronized void doOther() {
		System.out.println("doOther Begin");
		System.out.println("doOther Over");
	}
}

exam3

package exam3;
//面试题:doOther方法执行的时候需要等待doSome方法的结束吗?
	//不需要,因为MyClass对象是两个
public class Exam01 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		MyClass mc1 = new MyClass();
		MyClass mc2 = new MyClass();
		Thread t1 = new MyThread(mc1);
		Thread t2 = new MyThread(mc2);
		t1.setName("t1");
		t2.setName("t2");
		t1.start();
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}//保证t1先执行
		t2.start();
	}

}
class MyThread extends Thread{
	private MyClass mc;
	public MyThread(MyClass mc) {
		this.mc = mc;
	}
	public void run() {
		if(Thread.currentThread().getName().contentEquals("t1")) {
			mc.doSome();
		}
		if(Thread.currentThread().getName().contentEquals("t2")) {
			mc.doOther();
		}
	}
}
class MyClass{
	public synchronized void doSome() {
		System.out.println("doSome begin");
		try {
			Thread.sleep(1000*10);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("doSome over");
	}
	public synchronized void doOther() {
		System.out.println("doOther Begin");
		System.out.println("doOther Over");
	}
}

exam4

package exam4;
//面试题:doOther方法执行的时候需要等待doSome方法的结束吗?
	//需要,静态方法是类锁,不管你创建了几个对象,类锁只有1把
public class Exam01 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		MyClass mc1 = new MyClass();
		MyClass mc2 = new MyClass();
		Thread t1 = new MyThread(mc1);
		Thread t2 = new MyThread(mc2);
		t1.setName("t1");
		t2.setName("t2");
		t1.start();
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}//保证t1先执行
		t2.start();
	}

}
class MyThread extends Thread{
	private MyClass mc;
	public MyThread(MyClass mc) {
		this.mc = mc;
	}
	public void run() {
		if(Thread.currentThread().getName().contentEquals("t1")) {
			mc.doSome();
		}
		if(Thread.currentThread().getName().contentEquals("t2")) {
			mc.doOther();
		}
	}
}
class MyClass{
	public synchronized static void doSome() {
		System.out.println("doSome begin");
		try {
			Thread.sleep(1000*10);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("doSome over");
	}
	public synchronized static void doOther() {
		System.out.println("doOther Begin");
		System.out.println("doOther Over");
	}
}

实例十七:使用wait方法和notify方法实现生产者和消费者模式

package thread;

import java.util.ArrayList;
import java.util.List;

/*
	1.使用wait方法和notify方法实现生产者和消费者模式
	2.什么是生产者和消费者模式
		生产线程负责生产,消费线程负责消费
		生产线程和消费线程要达到均衡
		使用wait和notify方法
	3.不是线程对象的方法,java对象都有
	4.建立在synchronized线程安全基础上
	5.模拟需求:
		仓库采用List集合
		只能存储一个元素
		如果元素个数为0,表示仓库空了
		
 */
public class ThreadTest16 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		List list = new ArrayList();
		//创建两个线程对象
		//生产者线程
		Thread t1 = new Thread(new Producer(list));
		//消费者线程
		Thread t2 = new Thread(new Consumer(list));
		t1.setName("生产者线程");
		t2.setName("消费者线程");
		t1.start();
		t2.start();
	}

}
//生产线程
class Producer implements Runnable{
	private List list;//仓库
	public void run() {
		while(true) {
			//给仓库对象list加锁
			synchronized (list) {
				if(list.size()>0) {//当仓库满了时
					//当前线程进入等待状态,释放之前占有的List集合的锁
					try {
						list.wait();
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}else {
					list.add(new Object());
					System.out.println("生产");
					//唤醒消费者消费
					list.notify();
				}
			}
		}
	}
	public Producer(List list) {
		this.list = list;
	}
}
//消费线程
class Consumer implements Runnable{
	private List list;//仓库
	public void run() {
		while(true) {
			//给仓库对象list加锁
			synchronized (list) {
				if(list.size() == 0) {//当仓库空了时
					//当前线程进入等待状态,释放Consumer的锁
					try {
						list.wait();
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}else {
					list.remove(0);
					System.out.println("消费");
					//唤醒生产者消费
					list.notify();
				}
			}
		}
	}
	public Consumer(List list) {
		this.list = list;
	}
}

实例十八:线程定时器

package thread;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

/*
	使用定时器指定定时任务
 */
public class TimerTest01 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		//创建定时器对象
		Timer timer = new Timer();
		//Timer timer = new Timer(true);//指定守护线程的方式
		//指定定时任务
		//timer.schedule(定时任务,第一次执行时间,间隔多久执行一次);
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		Date firstTime = null;
		try {
			firstTime = sdf.parse("2020-03-14 09:30:00");
		} catch (ParseException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		timer.schedule(new LogTimerTask(), firstTime, 1000*10);
	}

}
//假设这是一个记录日志的定时任务
class LogTimerTask extends TimerTask{
	public void run() {
		System.out.println("完成了一次数据备份");
	}
}

实例十九:实现死锁

package deadLock;
/*
	死锁代码要会写
	死锁很难调试
	synchronized在开发中最好不要嵌套使用,容易形成死锁
 */

public class DeadLock {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Object o1 = new Object();
		Object o2 = new Object();
		//t1,t2共享o1,o2
		Thread t1 = new MyThread1(o1,o2);
		Thread t2 = new MyThread2(o1,o2);
		t1.start();
		t1.start();
	}

}
class MyThread1 extends Thread{
	Object o1;
	Object o2;
	public MyThread1(Object o1, Object o2) {
		this.o1 = o1;
		this.o2 = o2;
	}
	public void run() {
		synchronized(o1) {
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			synchronized(o2) {
				
			}
		}
	}
}
class MyThread2 extends Thread{
	Object o1;
	Object o2;
	public MyThread2(Object o1, Object o2) {
		this.o1 = o1;
		this.o2 = o2;
	}
	public void run() {
		synchronized(o2) {
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			synchronized(o1) {
				
			}
		}
	}
}

作者:余晖afterglow
来源链接:https://www.cnblogs.com/afterglow/p/14950981.html

版权声明:
1、JavaClub(https://www.javaclub.cn)以学习交流为目的,由作者投稿、网友推荐和小编整理收藏优秀的IT技术及相关内容,包括但不限于文字、图片、音频、视频、软件、程序等,其均来自互联网,本站不享有版权,版权归原作者所有。

2、本站提供的内容仅用于个人学习、研究或欣赏,以及其他非商业性或非盈利性用途,但同时应遵守著作权法及其他相关法律的规定,不得侵犯相关权利人及本网站的合法权利。
3、本网站内容原作者如不愿意在本网站刊登内容,请及时通知本站(javaclubcn@163.com),我们将第一时间核实后及时予以删除。


本文链接:https://www.javaclub.cn/java/69045.html

分享给朋友:

“java中的多线程Thread十九个实例带你轻松学会” 的相关文章

Java实现Email发送

一、前言最近将项目的登录密码从图形验证码改为了短信验证码,同时也将忘记密码时长度进行了修改,在修改时,想到了之前在一些国外的网站上,使用过邮箱接收验证码的情况,故想到何妨不自己尝试整合一下Java程序发送邮件信息呢,所以动手整合了Email的发送实例。二、Email发送协议想要在互联网上提供电子邮件...

java基础知识讲解(一)数据类型和运算符

java基础知识讲解(一)数据类型和运算符

Java是一种强类型语言,每个变量都必须声明其数据类型。 Java的数据类型可分为两大类:基本数据类型(primitive data type)和引用数据类型(reference data type)。 Java中定义了3类8种基本数据类型 数值型- b...

全面了解 Java 原子变量类

📦 本文以及示例源码已归档在 javacore 一、原子变量类简介 为何需要原子变量类 保证线程安全是 Java 并发编程必须要解决的重要问题。Java 从原子性、可见性、有序性这三大特性入手,确保多线程的数据一致性。 确保线程安全最...

Java日志框架那些事儿

Java日志框架那些事儿

在项目开发过程中,我们可以通过 debug 查找问题。而在线上环境我们查找问题只能通过打印日志的方式查找问题。因此对于一个项目而言,日志记录是一个非常重要的问题。因此,如何选择一个合适的日志记录框架也非常重要。在Java开发中,常用的日志记录框架有JDKLog、Log4J、LogBack、SLF4J...

Java对象的大小

基本数据的类型的大小是固定的,这里就不多说了。对于非基本类型的Java对象,其大小就值得商榷。 在Java中,一个空Object对象的大小是8byte,这个大小只是保存堆中一个没有任何属性的对象的大小。看 下面语句: Object ob = new Ob...

动车上的书摘-java对象流与序列化

动车上的书摘-java对象流与序列化

动车上的书摘-java对象流与序列化摘要: 摘要: 原创出处: http://www.cnblogs.com/Alandre/ 泥沙砖瓦浆木匠 希望转载,保留摘要,谢谢!钢笔不限贵便宜,书法是来自心对手的交流。-泥沙砖瓦浆木匠 一.对象序列化当需要存储相同类型的数据,选...

Java 容器 & 泛型:三、HashSet,TreeSet 和 LinkedHashSet比较

Java 容器 & 泛型:三、HashSet,TreeSet 和 LinkedHashSet比较

Writer:BYSocket(泥沙砖瓦浆木匠) 微博:BYSocket 豆瓣:BYSocket 上一篇总结了下ArrayList 、LinkedList和Vector比较,今天泥瓦匠总结下Hash 、LinkedList和Vector比较。其实大家都是...

java提高篇(二五)

java提高篇(二五)

      在java中与有两个类都提供了一个多种用途的hashTable机制,他们都可以将可以key和value结合起来构成键值对通过put(key,value)方法保存起来,然后通过get(key)方法获取相对应的value值。一个...

Java 基础之详解 Java IO

Java 基础之详解 Java IO

Java IO 基本概念 Java IO:即 Java 输入 / 输出系统。 区分 Java 的输入和输出:把自己当成程序, 当你从外边读数据到自己这里就用输入(InputStream/Reader), 向外边写数据就用输出(OutputStream/Writer)。...

JAVA IO 以及 NIO 理解

JAVA IO 以及 NIO 理解

由于Netty,了解了一些异步IO的知识,JAVA里面NIO就是原来的IO的一个补充,本文主要记录下在JAVA中IO的底层实现原理,以及对Zerocopy技术介绍。 IO,其实意味着:数据不停地搬入搬出缓冲区而已(使用了缓冲区)。比如,用户程序发起读操作,导致“ syscall...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。