Java基础总结—多线程篇

thread.start();

System.out.println(task.get()); //主线程获取分支线程的返回值

}

}

3、线程的生命周期

线程有时间片,才会运行,不然就抢夺时间片!

4、获取当前线程对象

Thread thread = Thread.currentThread(); //静态方法!获取当前线程对象

thread.getName() ; thread.setName() ;

5、线程休眠 Thread.sleep

package com.sqx;

/*

  • 线程休眠,中断线程线程休眠

  • */

public class ThreadSleep {

public static void main(String[] args) {

MyRunnable03 myRunnable03 = new MyRunnable03();

Thread t = new Thread(myRunnable03);

t.start();

System.out.println(“main线程开始”);

try {

Thread.sleep(1000*5); //main线程休眠5秒

} catch (InterruptedException e) {

e.printStackTrace();

}

// t.interrupt(); //方式一 : 中断分支线程,抛出异常sleep interrupted

// t.stop(); //直接杀死线程!栈都回收了,造成丢失数据!(该方法已经过时)

// 合理终止线程休眠(常用): 打个bool 标价,如果true就继续休眠,否则直接结束

myRunnable03.isSleep = false ;

}

}

class MyRunnable03 implements Runnable{

boolean isSleep = true ;

public void run() {

for( int i = 0 ; i < 10 ; i ++ ) {

if (isSleep == true){

System.out.println(“分支线程 ---- >” + i);

try {

Thread.sleep(1000*1);

} catch (InterruptedException e) {

e.printStackTrace();

}

}else{

System.out.println(“分支线程 ---- >” + i);

return ;

}

}

}

}

//线程休眠会使得当前线程放弃之前抢夺的时间片,从而线程进入就绪状态!

了解

  1. 线程优先级

public class ThreadPriority {

public static void main(String[] args) {

System.out.println(Thread.MAX_PRIORITY); //线程的最大优先级 10

System.out.println(Thread.MIN_PRIORITY); //线程的最小优先级 0

System.out.println(Thread.NORM_PRIORITY); //线程的默认优先级 5

System.out.println(Thread.currentThread().getPriority()); //获取当前线程的优先级

Thread.currentThread().setPriority(10); //设置当前线程的优先级为10

}

}

  1. 线程合并

Thread thread = new Thread(new MyRunnable05());

thread.start();

thread.join(); //讲thread线程合并到当前main线程中执行,栈不会改变仅仅是执行顺序!

  1. 线程让位

Thread.yield(); //当前线程让一下,当前线程此刻不回去抢占时间片,下一刻继续抢占

需要注意:Java的线程调度是抢占式调度模型,优先级高的线程抢占时间片的概率大!

二、线程安全 *

线程安全问题的产生需要满足:多线程并发、共享数据、共享数据有修改操作 ,如:两人同时取银行卡里的余额!

怎么解决线程安全问题?

  • 引入“线程同步机制”,也就是让线程排队,不再并发执行

  • 为了安全,可以牺牲一部分效率

了解 异步,同步编程模型

  • 异步编程模型 : 线程t1 ,t2各自执行各自的,t1不管t2,t2不管t1 ;谁也不需要等谁,本质就是多线程并发

  • 同步编程模型: 线程t1 ,t2需要满足 t2执行之前必须等待t1线程执行结束,两线程发生了等待关系 本质:线程排队执行

注意:异步就是并发,同步就是排队

Synchronized 同步代码块

//t1 、t2 两个线程同时向一个共享账户Account发起取款,如何避免线程的并发执行 ?

在我们的取款方法体上添加一层

public void withdraw(int count){

synchronized (需要排队的线程的共享对象){ //注:一个对象只有一把锁

方法体

}

}

当我们的t1 、t2线程调用withdraw方法时,先遇到synchronized(共享对象)的线程,会直接拿走锁池(lock)中共享对象的对象锁,从而执行方法体,此时共享对象的锁已经被占用,我们的另外一个线程只能等待共享对象的锁的归还,也就是等待上一个线程线程执行结束该同步代码块,执行结束才会归还锁,我们未执行该方法的线程再去获取锁,去执行方法!

为什么非得传入共享对象?

因为传入一个共享对象,两个线程中共享的这一个对象的对象锁被拿走,另一个对象无法获取,因此无法进入同步代码块!但是如果传入的是非共享对象,则一个线程把这个非共享对象的锁拿走,并不影响另外一个线程任何操作! (共享可以看作,两线程共用这一个)

局部变量是线程安全的!因为存储在栈中,数据不共享,常量不可修改也是线程安全的!

静态变量和实例变量则是分别在方法区和队中,存在数据共享,可能会导致线程不安全问题

Synchrnoized三种写法

方式一:同步代码块

public void withdraw(int count){

synchronized (需要排队的线程的共享对象){ //优点:灵活,哪里需要加哪里

方法体

}

}

方式二:实例方法上添加Synchronized

public synchronized void withdraw(int count){ //默认是方法体中的所有都需要同步,而且共享对象为this

//优点:省代码

}

方式三:在类上添加Synchronized

//表示找类锁,一个类一个锁,即使创建100个对象也仍然只有1个锁!

扩展:对象锁保证的是实例变量的安全、类锁保证的是静态变量的安全!

三、死锁

实现一个死锁,由于死锁不会报错,因此很难调试,我们只有会写死锁,以后才能注意 !

package com.sqx;

/*

  • 实现一个死锁!

  • */

public class DeadLock {

public static void main(String[] args) {

Object o1 = new Object();

Object o2 = new Object();

MyThread1 thread1 = new MyThread1(o1, o2);

MyThread2 thread2 = new MyThread2(o1, o2);

thread1.start();

thread2.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){

synchronized (o2){ //等待o2锁的释放

}

}

}

}

class MyThread2 extends Thread{

Object o1 ;

Object o2 ;

public MyThread2(Object o1, Object o2){

this.o1 = this.o1;

this.o2 = this.o2;

}

public void run(){

synchronized (o2){ //等待o1锁的释放

synchronized (o1){

}

}

}

}

四、守护线程

守护线程一般在默默运行,用户线程全部结束,守护线程也会自动结束!

线程分为两类:

  1. 用户线程

  2. 守护线程

创建一个线程,直接设置为守护线程即可

t.setDeamon(true) //讲当前t线程设置为守护线程!

五、定时器

实际开发中,每隔多久执行一段特定的程序,这种需求是很常见的!

方式一:Thread.Sleep, 设置睡眠多长时间,执行任务,最原始的方式 ;

方法二:Java类库中写好的一个定时器java.util.Timer,可以直接用,但是用的少,框架一般都带自己的定时器,

方式三 : 使用最多的就是spring框架当中提供的springTask框架,只需简单的配置就可以完成定时器(底层还是方式二);

//方式二的实现原理

public class TimeTest {

public static void main(String[] args) throws ParseException {

Timer timer = new Timer(); //创建定时对象

//Timer timer = new Timer(true); Timer以守护线程的形式运行

//指定定时任务(要执行的任务,第一次执行时间,间隔多久执行一次)

SimpleDateFormat dateFormat = new SimpleDateFormat(“yyyy-MM-dd HH:mm:ss”);

Date FirstDate = dateFormat.parse(“2021-9-28 17:40:00”);

timer.schedule(new LogTask(),FirstDate,1000*10); //可以改为匿名内部类方式

}

}

class LogTask extends TimerTask{

public void run() {

//定时执行的任务

System.out.println(“到时间了!”);

}

}

六、wait和notify

wait() 和 notify () 是Object 的方法 , 通常结合synchrnoized使用

  • wait()意思是说,我等会儿再用这把锁(对象锁!),CPU也让给你们,我先休息一会儿!

  • notify()意思是说,我用完了,你们谁用?

测试代码:

package com.sqx;

public class WaitTest {

public static void main(String[] args) {

Object obj = new Object() ;

MyThread01 t1 = new MyThread01(obj);

MyThread02 t2 = new MyThread02(obj);

t1.start();

t2.start();

}

}

class MyThread01 extends Thread{

Object object ;

public MyThread01(Object object) {

this.object = object ;

}

@Override

public void run() {

synchronized (object){

System.out.println(“T1线程执行”);

try {

object.wait();

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println(“T1线程结束!”);

}

}

}

class MyThread02 extends Thread{

Object object ;

public MyThread02(Object object) {

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值