Thread
- 实例一:判断程序除垃圾回收外,有几个线程
- 实例二:实现线程的第一种方式继承java.lang.Thread类
- 实例三:实现线程的第二种方式实现java.lang.Runnable接口
- 实例四:采用匿名内部类的方式实现线程
- 实例五:获取当前线程对象及相关操作
- 实例六:关于线程的sleep方法
- 实例七:sleep相关面试题
- 实例八:如何唤醒睡眠(sleep)中的线程
- 实例九:强制终止一个线程
- 实例十:合理的终止一个线程
- 实例十一:关于线程优先级
- 实例十二:线程的让位方法
- 实例十三:线程合并
- 实例十四:守护线程
- 实例十五:实现线程的第三种方式:实现Callable接口
- 实例十六:线程同步相关面试题
- 实例十七:使用wait方法和notify方法实现生产者和消费者模式
- 实例十八:线程定时器
- 实例十九:实现死锁
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对象上等待的线程
一图流:
实例一:判断程序除垃圾回收外,有几个线程
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) {
}
}
}
}