一、和线程调度有关的方法
1.void setPriority(int newPriority) 设置线程的优先级
2.int getPriority() 获取线程优先级
package com.java.javase.Thread; public class ThreadTest08 { public static void main(String[] args) { Thread currentThread=Thread.currentThread(); System.out.println(currentThread.getName()+"线程的默认优先级是:"+currentThread.getPriority()); Thread t=new Thread(new MyThread8()); t.setName("t"); t.start(); } } class MyThread8 implements Runnable{ @Override public void run() { System.out.println(Thread.currentThread().getName()+"线程的默认优先级是:"+Thread.currentThread().getPriority()); } }输出结果:
main线程的默认优先级是:5
t线程的默认优先级是:53.Thread.yield() 当前线程暂停一下
package com.java.javase.Thread; public class ThreadTest { public static void main(String[] args) { Thread t=new Thread(new MyRunable()); t.setName("t"); t.start(); for(int i=0;i<100;i++){ System.out.println(Thread.currentThread().getName()+"--->"+i); } } } class MyRunable implements Runnable{ @Override public void run() { for(int i=0;i<100;i++){ // 每10个让位一次 if(i%10==0){ Thread.yield(); // 当前线程暂停一下,让给主线程 } System.out.println(Thread.currentThread().getName()+"--->"+i); } } }4.void join() 合并线程
package com.java.javase.Thread; public class ThreadTest { public static void main(String[] args) throws InterruptedException { System.out.println("main begin"); Thread t=new Thread(new MyRunable()); t.setName("t"); t.start(); // 合并线程 t.join(); // t合并到当前线程中,当前线程受到阻塞,t线程执行直到结束,栈之间进行了协调 System.out.println("main over"); } } class MyRunable implements Runnable{ @Override public void run() { for(int i=0;i<5;i++){ System.out.println(Thread.currentThread().getName()+"--->"+i); } } }输出结果:
main begin
t--->0
t--->1
t--->2
t--->3
t--->4
main over
二、线程同步机制
不使用线程同步机制下—模拟两个线程对同一个账户取款
账户类
package com.java.javase.ThreadSafe; public class Account { private String no; private double balance; public Account() { } public Account(String no, double balance) { this.no = no; this.balance = balance; } public String getNo() { return no; } public void setNo(String no) { this.no = no; } public double getBalance() { return balance; } public void setBalance(double balance) { this.balance = balance; } // 提供一个取款的方法 public void withDraw(double money){ // 未使用线程同步机制 // t1和t2并发这个方法(t1和t2是两个栈,两个栈操作堆中同一个对象) double before=this.getBalance(); double after=before-money; this.setBalance(after); } }线程类
package com.java.javase.ThreadSafe; public class AccountThread extends Thread { // 两个线程必须共享同一个账户对象 private Account act; public AccountThread(Account act){ this.act=act; } @Override public void run() { double money=5000; act.withDraw(money); System.out.println(Thread.currentThread().getName()+"对001账户取款成功 "+"剩余余额:"+act.getBalance() ); } }测试类
package com.java.javase.ThreadSafe; public class Test { public static void main(String[] args) { // 相当于同一张银行卡,属性有卡的账号和余额 Account act=new Account("001",10000); // 两个栈操作堆中同一个对象,相当于两个人对同一张银行卡进行操作 Thread t1=new AccountThread(act); Thread t2=new AccountThread(act); t1.setName("t1"); t2.setName("t2"); t1.start(); t2.start(); } }安全情况下:
t2对001账户取款成功 剩余余额:0.0
t1对001账户取款成功 剩余余额:5000.0但是会出现线程安全问题:
t2对001账户取款成功 剩余余额:5000.0
t1对001账户取款成功 剩余余额:5000.0如何使用线程同步机制解决线程安全问题:
我们只需要将账户类中的取款方法改为:
package com.java.javase.ThreadSafe; public class Account { private String no; private double balance; public Account() { } public Account(String no, double balance) { this.no = no; this.balance = balance; } public String getNo() { return no; } public void setNo(String no) { this.no = no; } public double getBalance() { return balance; } public void setBalance(double balance) { this.balance = balance; } // 提供一个取款的方法 public void withDraw(double money) { // 使用线程同步机制 synchronized (this){ // 这几行代码必须是排队的,不能并发 // 线程同步机制的语法: // synchronized (){线程同步代码块} // ()中的内容相当关键 try{ Thread.sleep(1000); }catch (InterruptedException e){ } double before=this.balance; double after=before-money; this.setBalance(after); } } }synchronized执行原理:
1.假设t1和t2线程并发,开始执行同步代码块的时候,肯定有一个先有一个后
2.假设t1先执行了,遇到了synchronized关键字,这个时候自动找”后面共享对象“的对象锁,找到之后占有这把锁,然后执行同步代码块中的程序,在程序执行过程中一直都是占有这把锁的,直到同步代码块执行结束,这把锁才会被释放
3.假设t1已经占有这把锁,此时t2也遇到synchronized关键字,也会去占有后面共享对象的这把锁,结果这把锁已经被t1占有,t2只能在同步代码块外面等待t1的结束,直到t1把同步代码块执行结束了,t1归还了这把锁,此时t2终于等到这把锁,然后t2占有这把锁,进入同步代码块执行程序,这样就达到了线程排队执行
synchronized可以出现实例方法上:
package com.java.javase.ThreadSafe; public class Account { private String no; private double balance; public Account() { } public Account(String no, double balance) { this.no = no; this.balance = balance; } public String getNo() { return no; } public void setNo(String no) { this.no = no; } public double getBalance() { return balance; } public void setBalance(double balance) { this.balance = balance; } // 提供一个取款的方法 public synchronized void withDraw(double money) { double before=this.balance; double after=before-money; try{ Thread.sleep(1000); }catch (InterruptedException e){ } this.setBalance(after); } }
三、练习题
练习1:
package com.java.javase.Thread; public class ThreadTest { public static void main(String[] args) throws InterruptedException { MyClass mc=new MyClass(); Thread t1=new MyThread(mc); Thread t2=new MyThread(mc); t1.setName("t1"); t2.setName("t2"); t1.start(); Thread.sleep(1000); // 确保t1线程先执行 t2.start(); } } class MyThread extends Thread{ private MyClass mc; public MyThread(MyClass mc){ this.mc=mc; } public void run(){ if(Thread.currentThread().getName().equals("t1")){ mc.doSome(); }else if(Thread.currentThread().getName().equals("t2")){ mc.doOther(); } } } class MyClass{ public synchronized void doSome(){ System.out.println("doSome begin"); try{ Thread.sleep(1000*10); }catch (InterruptedException e){ e.printStackTrace(); } System.out.println("doSome over"); } public void doOther(){ System.out.println("doOther begin"); System.out.println("doOther over"); } }输出结果:
doSome begin
doOther begin
doOther over
doSome over在上题中的doOther方法上加上synchronized,结果会怎么样?
package com.java.javase.Thread; public class ThreadTest { public static void main(String[] args) throws InterruptedException { MyClass mc=new MyClass(); Thread t1=new MyThread(mc); Thread t2=new MyThread(mc); t1.setName("t1"); t2.setName("t2"); t1.start(); Thread.sleep(1000); // 确保t1线程先执行 t2.start(); } } class MyThread extends Thread{ private MyClass mc; public MyThread(MyClass mc){ this.mc=mc; } public void run(){ if(Thread.currentThread().getName().equals("t1")){ mc.doSome(); }else if(Thread.currentThread().getName().equals("t2")){ mc.doOther(); } } } class MyClass{ public synchronized void doSome(){ System.out.println("doSome begin"); try{ Thread.sleep(1000*10); }catch (InterruptedException e){ e.printStackTrace(); } System.out.println("doSome over"); } public synchronized void doOther(){ System.out.println("doOther begin"); System.out.println("doOther over"); } }输出结果:
doSome begin
doSome over
doOther begin
doOther oversynchronized 出现在静态方法上:
package com.java.javase.Thread; public class ThreadTest { public static void main(String[] args) throws InterruptedException { MyClass mc=new MyClass(); Thread t1=new MyThread(mc); Thread t2=new MyThread(mc); t1.setName("t1"); t2.setName("t2"); t1.start(); Thread.sleep(1000); // 确保t1线程先执行 t2.start(); } } class MyThread extends Thread{ private MyClass mc; public MyThread(MyClass mc){ this.mc=mc; } public void run(){ if(Thread.currentThread().getName().equals("t1")){ mc.doSome(); }else if(Thread.currentThread().getName().equals("t2")){ mc.doOther(); } } } class MyClass{ public synchronized static void doSome(){ System.out.println("doSome begin"); try{ Thread.sleep(1000*10); }catch (InterruptedException e){ e.printStackTrace(); } System.out.println("doSome over"); } public synchronized static void doOther(){ System.out.println("doOther begin"); System.out.println("doOther over"); } }doSome begin
doSome over
doOther begin
doOther over
四、死锁
package com.java.javase.deadLock;
public class ThreadTest {
public static void main(String[] args) throws InterruptedException {
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();
t2.start();
}
}
class MyThread1 extends Thread{
Object o1;
Object o2;
public MyThread1(Object o1,Object o2){
this.o1=o1;
this.o2=o2;
}
@Override
public void run() {
synchronized (o1){
try {
Thread.sleep(1000*5);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (o2){
}
}
}
}
class MyThread2 extends Thread{
Object o1;
Object o2;
public MyThread2(Object o1,Object o2){
this.o1=o1;
this.o2=o2;
}
@Override
public void run() {
synchronized (o2){
try {
Thread.sleep(1000*5);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (o1){
}
}
}
}
五、 守护线程和定时器
package com.java.javase.Thread; public class ThreadTest { public static void main(String[] args) throws InterruptedException { Thread t1=new MyThread(); t1.setName("备份数据的线程"); // 启动线程之前,将线程设置为守护线程 t1.setDaemon(true); t1.start(); // 主线程:用户线程 for(int i=0;i<10;i++){ System.out.println(Thread.currentThread().getName()+"---"+i); Thread.sleep(1000); } } } class MyThread extends Thread{ @Override public void run() { // 即使是死循环,但由于该线程是守护线程,当用户线程结束,守护线程自动停止 int i=0; while (true) { System.out.println(Thread.currentThread().getName() + "---" + (i++)); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }备份数据的线程---7
备份数据的线程---8
main---8
main---9
备份数据的线程---9
备份数据的线程---10Process finished with exit code 0
定时器:
package com.java.javase.Timer; 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) throws Exception{ SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Date firstTime=sdf.parse("2021-11-01 14:36:00"); // 创建定时器对象 Timer timer=new Timer(); // 三个参数:指定定时任务,第一次执行时间,间隔多久执行一次 timer.schedule(new LogTimerTask(),firstTime,1000*10); } } // 编写一个定时任务类 // TimerTask实现了Runnable接口 class LogTimerTask extends TimerTask{ @Override public void run() { SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS"); String strTime=sdf.format(new Date()); System.out.println(strTime+":完成了一次数据备份"); } }2021-11-01 14:36:00 016:完成了一次数据备份
2021-11-01 14:36:10 019:完成了一次数据备份
2021-11-01 14:36:20 035:完成了一次数据备份
六、实现线程的第三种方式 ,实现Callable接口
package com.java.javase.Thread;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class ThreadTest {
public static void main(String[] args) throws InterruptedException, ExecutionException {
// 创建一个"未来任务类"对象
// 需要给一个Callable接口实现类对象
FutureTask futureTask=new FutureTask(new Callable() {
@Override
public Object call() throws Exception {
// call()方法就相当于run方法,只不过这个有返回值
// 线程执行一个任务,执行之后可能会有一个执行结果
System.out.println("call begin");
Thread.sleep(1000*10);
System.out.println("call over");
return new Object();
}
});
// 创建线程对象
// 这里是main方法,在主线程中
// 在主线程中怎么获取t线程的返回结果?
// get()方法的执行会导致当前线程阻塞
Thread t=new Thread(futureTask);
t.start();
futureTask.get();
// main方法的这里的程序要想执行必须等待get()方法的结束
// 而get()方法可能需要很久
System.out.println("拿到执行结果");
}
}
七、Object类中的wait和notify方法 —生产者和消费者模式
package com.java.javase.ProducerAndCustomer;
import java.util.ArrayList;
import java.util.List;
// 使用wait方法和notify方法实现“生产者和消费者模式”
public class ThreadTest {
public static void main(String[] args) {
List list=new ArrayList();
Thread t1=new Thread(new Producer(list));
Thread t2=new Thread(new Customer(list));
t1.setName("生产者线程");
t2.setName("消费者线程");
t1.start();
t2.start();
}
}
// 生产线程
class Producer implements Runnable{
// 仓库
private List list;
public Producer(List list) {
this.list = list;
}
@Override
public void run() {
while(true){
// 给仓库对象list加锁
synchronized (list){
// 大于0,说明仓库中已经有一个元素了
if(list.size()>0){
try {
// 当前线程进入等待状态,并且释放Producer之前占有的list集合的锁
list.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Object obj = new Object();
list.add(obj);
System.out.println(Thread.currentThread().getName() + "-----生产了一个" + obj);
list.notifyAll();
}
}
}
}
// 消费线程
class Customer implements Runnable{
private List list;
public Customer(List list) {
this.list = list;
}
@Override
public void run() {
while(true){
synchronized (list){
if(list.size()==0){
try {
list.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Object obj=list.remove(0);
System.out.println(Thread.currentThread().getName()+"-----消费了一个"+obj);
list.notifyAll();
}
}
}
}



