5. Thread类中常用的一些方法
static void sleep:使当前线程阻塞多少毫秒--线程休眠
yield:当前线程让出cpu参与下次竞争--使用yield线程出现交换执行的频率变高了
join加入当前线程上(插入的线程执行完毕后,当前的线程才会执行)
setDaemon()设置线程为守护线程(当所有的线程执行完毕后,守护线程也会终止)
// sleep--阻塞多少时间
public class Method extends Thread{
@Override
public void run() {
for (int i = 0; i < 20; i++){
System.out.println(Thread.currentThread().getName()+"-->"+i);
//休眠1秒--每隔一秒执行
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("------------------");
}
}
}
//join--等待线程
public static void main(String[] args) throws InterruptedException {
Method thread1 = new Method();
thread1.setName("线程1");
Method thread2 = new Method();
thread2.setName("线程2");
thread1.start();
thread2.start();
thread1.join();// 加入到主线程上--线程1执行完之后再执行main线程.如果主线程需要等待1和2线程的执行结果 做下一步操作时。
//thread2.join();
for (int i = 0; i < 20; i++) {
//Thread.sleep(10);
System.out.println("main线程" + i);
}
-------------------------------------------------------------------------------
//setDaemon--守护线程
Method thread1 = new Method();
thread1.setName("线程1");
thread1.setDaemon(true);//设置thread1为守护线程--以主线程为主,当主线程停息的时候守护线程会出现,主线程完毕之前,守护线程也会终止。
//比如下面的for循环,虽然i打印输出了但是它还要进行判断和i++,在执行判断这个过程时,守护线程就排上了用场
thread1.start();
for (int i = 0; i < 20; i++) {
//Thread.sleep(10);
System.out.println("main线程" + i);
}
thread1.join();// 加入到主线程上--线程1执行完之后再执行main线程.如果主线程需要等待1和2线程的执行结果 做下一步操作时。
//thread2.join();
for (int i = 0; i < 20; i++) {
//Thread.sleep(10);
System.out.println("main线程" + i);
}
-------------------------------------------------------------------------------
Method thread1 = new Method();
thread1.setName("线程1");
thread1.setDaemon(true);//设置thread1为守护线程--以主线程为主,当主线程停息的时候守护线程会出现,主线程完毕之前,守护线程也会终止。
//比如下面的for循环,虽然i打印输出了但是它还要进行判断和i++,在执行判断这个过程时,守护线程就排上了用场
thread1.start();
for (int i = 0; i < 20; i++) {
//Thread.sleep(10);
System.out.println("main线程" + i);
}
6. 解决线程安全问题
6.1什么情况下会出现线程安全问题
当多个线程操作同一个资源时,则会出现线程安全问题
6.2java如何解决线程安全问题
第一种方式:使用synchronized自动锁
第二种方式:使用Lock手动锁
使用锁相对于把原来的异步转换为同步操作。
第一种:使用synchroonized关键字解决
它可以使用在方法上,也可以使用在代码块中。
synchroinzed(共享锁对象){
同步代码块。
}
public class MyRunnableAL implements Runnable{
private int tick = 100;
private Object obj = new Object();
@Override
public void run() {
while (true){
//使用在代码块中
synchronized (obj){
if (tick>0){
tick--;
System.out.println(Thread.currentThread().getName()+" tick:"+tick);
}else {
break;
}
}
}
}
}
-----------------------------------------------------------------------------
private int tick = 100;
//使用在方法上
@Override
public void run() {
while (true){
setTick();
if (tick<=0){
break;
}
}
}
public synchronized void setTick(){
if (tick>0){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
tick--;
System.out.println(Thread.currentThread().getName()+" tick:"+tick);
}
}
-------------------------------------------------------------------------------
public class Test02 {
public static void main(String[] args) {
MyRunnableAL myRunnableAL1 = new MyRunnableAL();
new Thread(myRunnableAL1,"A").start();
new Thread(myRunnableAL1,"B").start();
new Thread(myRunnableAL1,"C").start();
new Thread(myRunnableAL1,"D").start();
}
}
第二种:使用Lock手动
Lock是一个接口,实现类ReentrantLock
private int tick = 100;
//手动加锁Lock
private Lock lock = new ReentrantLock();
@Override
public void run() {
while (true) {
try {
//加锁
lock.lock();
if (tick > 0) {
tick--;
System.out.println("当前线程对象的名字为:" + Thread.currentThread().getName() + "----剩余:" + tick + "张票");
} else {
break;
}
} finally {//确保解锁---防止死锁---finally语句块:无论怎样都会执行的语句块
//解锁
lock.unlock();
}
}
}
6.3synchroinzed自动锁和Lock手动锁的区别
synchroinzed可以使用在方法上和代码块中,自动加锁和释放锁,不会出现锁死现象。
Lock只能用在代码块中,需要手动加锁和释放锁,如果不释放锁,会被锁死。
比较灵活。释放锁要放在finally代码块中。
7. 线程死锁问题
线程A拥有所资源a,希望获取到锁资源b,线程B拥有资源b,希望获取锁资源a。
两个线程互相拥有对方希望获取的锁资源。可能会出现程序堵塞。从而造成死锁。
解决:
1.不要使用锁嵌套。
2.设置超时时间。--Lock类中tryLock
3.使用安全java.until.controller下的类。
8. 线程通信
wait方法(等待线程)和notify方法(唤醒线程)--必须用在synchronized自动锁中
package com.wjy.waitAndNotify;
public class BankCard {
private double balance;
private boolean flag;//true:有钱 false:没钱
//存款--如果有钱先取走(线程等待)
public synchronized void cun(double money){
if (flag==true){
try {
//属于Object类的方法。进入等待队列 并释放拥有的锁
wait();//线程等待
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
//如果没钱,则存款
balance+=money;
System.out.println(Thread.currentThread().getName()+"存钱成功,余额为:"+balance);
//设置有钱标志--代表可以取钱
flag=true;
//唤醒线程--唤醒等待队列中的某个线程
notify();
}
//取款--如果没钱先线程等待
public synchronized void qu(double money){
//没钱--先等待
if (flag==false){
try {
wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
//有钱--取钱
balance-=money;
System.out.println(Thread.currentThread().getName()+"取钱成功,余额为:"+balance);
//设置没钱标志--代表可以存钱
flag=false;
notify();
}
}
package com.wjy.waitAndNotify;
public class CunThread extends Thread{
private BankCard bankCard;
//构造方法--确保都是使用的同一张卡
public CunThread(BankCard bankCard){
this.bankCard=bankCard;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
bankCard.cun(300);
}
}
}
package com.wjy.waitAndNotify;
public class QuThread extends Thread{
private BankCard bankCard;
public QuThread(BankCard bankCard){
this.bankCard=bankCard;
}
@Override
public void run() {
for (int i = 0; i < 100; i++){
bankCard.qu(300);
}
}
}
package com.wjy.waitAndNotify;
public class Test01 {
public static void main(String[] args) {
BankCard bankCard = new BankCard();
CunThread cunThread = new CunThread(bankCard);
cunThread.setName("c");
QuThread quThread = new QuThread(bankCard);
quThread.setName("q");
cunThread.start();
quThread.start();
}
}
9. 线程池
new:新建状态
runnable:就绪状态和运行状态
blocked:堵塞状态
waiting:等待状态
timed_waiting:时间等待
terminated:终止
通过调用不同的方法相互转换
标签:Thread,--,死锁,线程,thread1,new,public From: https://blog.csdn.net/m0_74194490/article/details/140191255