5. Thread类中常用的一些方法
5.1 线程休眠方法
public class MyThread extends Thread{ @Override public void run() { for (int i = 0; i <20 ; i++) { try { //秒杀--- Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } System.out.println(Thread.currentThread().getName()+"~~~~~~~~~~~~~~~"+i); } } }
5.2 放弃 yieId方法
yield 当前线程让出cpu-参与下次的竞争
public class MyThread extends Thread{ @Override public void run() { for (int i = 0; i <20 ; i++) { System.out.println(Thread.currentThread().getName()+"~~~~~~~~~~~~~~~"+i); Thread.yield();//当前线程让出cpu参与下次的竞争。 System.out.println("~~~~~~~~~~~~~~~~"); } } }
5.3 join加入当前线程上
插入的线程执行完毕后,当前线程才会执行。
public class Test {
public static void main(String[] args) throws InterruptedException {
MyThread t1=new MyThread();
t1.setName("线程A");
MyThread2 t2=new MyThread2();
t2.setName("线程B");
t1.start();
t2.start();
t1.join(); //t1加入主线程上,主线程需要等t1执行完毕后才会执行. 如果主线程需要等带t1和t2线程的执行结果 做下一步操作时。
for (int i = 0; i <20 ; i++) {
Thread.sleep(10);
System.out.println("main~~~~~~~~~~~~~~~~~~~~~"+i);
}
}
}
5.4 setDaemon()
设置线程为守护线程,当所有线程执行完毕后,守护线程也会终止。
//JDK--默认就有一个守护线程.GC垃圾回收。
public class Test {
public static void main(String[] args) throws InterruptedException {
MyThread t1=new MyThread();
t1.setName("线程A");
t1.setDaemon(true);//设置t1为守护线程
t1.start();
for (int i = 0; i <20 ; i++) {
System.out.println("main~~~~~~~~~~~~~~~~~~~~~"+i);
}
}
}
6.解决线程安全问题
java程序中如何加锁: synchronized和Lock锁
6.1什么情况下会出现线程安全问题
线程不安全的问题主要出现在多线程环境中,当一个或多个线程在没有适当同步的情况下,同时访问共享资源或数据时,就可能引发线程不安全的问题。这是因为每个线程都有自己的执行路径和速度,它们可能同时读写同一个变量或对象的状态,导致数据的不一致或不可预测的行为。
6.2如何解决线程不安全问题?
提供了两种方式:第一种:使用synchronized自动锁 第二种: 使用Lock手动锁。使用锁相对于把原来的异步转换为同步操作。 需要注意的是,解决问题的关键在于使用同一个锁对象来确保同步。如果多个线程使用不同的锁对象,则无法解决线程安全问题。
6.2.1同步代码块
格式:synchronized(对象) {
需要被同步的代码;
}
public void run() {
while (true) {
synchronized (this){
if(ticket > 0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(Thread.currentThread().getName() + "正在出售第" + ticket + "张票");
ticket--;
}else {
break;
}
}
}
}
6.2.2同步方法
格式:把同步(synchronized)加在方法上。
public void run() {
while (ticket>0) {
sellTicket();
}
}
public synchronized void sellTicket() {
if(ticket > 0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(Thread.currentThread().getName() + "正在出售第" + ticket + "张票");
ticket--;
}
}
6.2.3加锁Lock解决问题
Lock它是一个接口,它的实现类。ReentrantLock
public class SellTicket implements Runnable {
private int tick = 100;
private Lock l = new ReentrantLock();
//synchronized使用在方法那么它的共享锁为this
@Override
public void run() {
while (true) {
try {
l.lock();//加锁
if (tick > 0) {
try {
Thread.sleep(20);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
tick--;
System.out.println(Thread.currentThread().getName() + "卖了一张票;剩余:" + tick + "张");
} else {
break;
}
} finally {
l.unlock();//解锁
}
}
}
}
7.死锁
什么是死锁?
线程A拥有锁资源a,希望获取锁资源b. 线程B拥有锁资源b,希望获取锁资源a。 线程A和B拥有对方像获取的锁资源。等待线程---永久等待。---从而造成死锁问题。
线程一
public class Boy extends Thread {
@Override
public void run() {
synchronized (LockObject.lockb) { // 修改为与女孩线程相同的锁获取顺序
System.out.println("男孩获取锁a");
synchronized (LockObject.locka) {
System.out.println("男孩获取锁b");
System.out.println("男孩开始画画");
}
}
}
}
线程二
public class Girl extends Thread {
@Override
public void run() {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
synchronized (LockObject.locka) {
System.out.println("女孩获取锁a");
synchronized (LockObject.lockb) {
System.out.println("女孩获取锁b");
System.out.println("女孩开始画画");
}
}
}
}
解决办法:
1. 不要使用锁嵌套。
2. 设置超时时间。--Lock类中tryLock.
3. 使用安全java.util.concurrent下的类。
8.线程通信
wait() 方法:
wait()
方法使当前线程进入等待状态,同时释放它所持有的锁(通过synchronized
获取的锁),直到其他线程调用相同对象的notify()
或notifyAll()
方法唤醒该线程。- 在调用
wait()
方法前,线程必须通过获取对象的锁来确保同步。notify() 方法:
notify()
方法用于唤醒因调用对象的wait()
方法而处于等待状态的单个线程。如果有多个线程在等待,那么哪个线程被唤醒是不确定的,取决于 JVM 的实现。- 类似地,
notifyAll()
方法唤醒所有等待的线程。
代码示例:
public class BankCard {
private double balance;
private boolean flag;//true:有钱 false:没钱
public synchronized void cun(double money){
if(flag==true){
try {
wait();//属于Object类中。 进入等待队列 并且释放拥有的锁
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
//+余额
balance+=money;
//设置有钱标志
flag=true;
//唤醒--唤醒等待队列中的某个线程
notify();
System.out.println(Thread.currentThread().getName()+"往卡中存入了:"+money+";卡中余额:"+balance);
}
public synchronized void qu(double money){
if(flag==false){
try {
wait(); //放入等待队列中。
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
balance-=money;
flag=false;
notify();
System.out.println(Thread.currentThread().getName()+"从卡中取出了:"+money+";卡中余额:"+balance);
}
}
public class CunThread extends Thread{
private BankCard bankCard;
public CunThread(BankCard bankCard){
this.bankCard=bankCard;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
bankCard.cun(1000);
}
}
}
package com.ykq.demo06;
public class QuThread extends Thread{
private BankCard bankCard;
public QuThread(BankCard bankCard){
this.bankCard=bankCard;
}
@Override
public void run() {
for (int i = 0; i <10 ; i++) {
bankCard.qu(1000);
}
}
}
public static void main(String[] args) {
BankCard bankCard=new BankCard();
CunThread c=new CunThread(bankCard);
c.setName("张三");
QuThread q=new QuThread(bankCard);
q.setName("李四");
c.start();
q.start();
}
9. 线程状态
NEW,====新建状态。
RUNNABLE,===>就绪状态和运行状态
BLOCKED,===>堵塞状态
WAITING,====>等待状态
TIMED_WAITING,===>时间等待
TERMINATED;===终止。
10. 面试题
1. syn和lock的区别?
syn可以使用代码块和方法。自动加锁和释放锁。不会出现死锁问题。lock它只能使用在代码块中。需要手动加锁和释放锁。如果不释放锁,死锁问题。灵活。它的释放锁必须放finally.
2. 什么是死锁和如何避免死锁。文中已有答案
3. 线程的状态?文中已有答案
4. notify和notifyAll的区别。notify()和notifyAll()都是Java中用于唤醒等待在特定对象上的线程的方法,它们都用于处理多线程编程中的同步问题。然而,它们之间存在一些关键的区别:
用途:notify()通常用于唤醒单个等待在该对象上的线程,而notifyAll()用于唤醒所有等待在该对象上的线程。
阻塞模式:使用notify()唤醒单个线程时,其他线程不会被阻塞,可以继续执行。使用notifyAll()唤醒所有线程时,所有正在等待该对象的线程都会被唤醒,然后它们会尝试重新进入同步代码块或方法。
线程安全性:notifyAll()方法在唤醒所有线程时需要特别小心,因为如果有多个线程同时尝试进入同步代码块或方法,可能会导致数据的不一致性。相比之下,notify()在唤醒单个线程时更加安全。
性能:使用notifyAll()可能会导致更多的线程重新进入同步代码块或方法,这可能会消耗更多的CPU资源。相比之下,使用notify()可以更快地唤醒单个线程,因此可能在某些情况下提供更好的性能。5. wait和sleep方法。
1. wait来自于Object。sleep来自于Thread
2. wait必须放入同步代码块中,sleep可以在任何地方执行。
3. wait会释放锁资源。sleep不会释放锁。
4. wait需要手动唤醒。sleep时间到了自动唤醒。
6.Thread类中常用方法。文中已有答案
还有一点没有写完,明天补上!!!
标签:Java,synchronized,Thread,--,void,线程,唤醒,public From: https://blog.csdn.net/As_Yua/article/details/140188267