Thread的yield()方法:
yield方法是让出当前线程的cpu时间,所有的线程公平竞争
例如:
public class ThreadDemo01 {
public static void main(String[] args) {
YieldTest yt1=new YieldTest();
yt1.setName("十堰");
YieldTest yt2=new YieldTest();
yt2.setName("苍穹");
yt1.start();
yt2.start();
}
}
class YieldTest extends Thread{
@Override
public void run(){
for (int i = 1; i < 100; i++) {
System.out.println(getName()+"------"+i);
if (i%10==0){
yield();//当i取余10等于0的时候,让出当前线程的cpu时间片
}
}
}
}
Thread的join():
用于等待指定线程结束之后才可以执行该线程
例如:图片的缓存和显示
public class ThreadDemo02 {
//定义一个开关,用于表示线程是否正常下载
public static boolean isFinish=false;
public static void main(String[] args) {
//图片下载线程
Thread download=new Thread(){
@Override
public void run() {
System.out.println("download:开始下载");
for (int i=0;i<=100;i++){
System.out.println("download:已下载"+i+"%");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("download:图片下载完成----");
isFinish=true;//用于表示线程执行下载结束,表示正常下载
}
};
//图片显示线程
Thread show=new Thread(){
@Override
public void run() {
try {
//System.out.println("show:图片要显示了----");
System.out.println("show:正在等在下载----");
//规定当下载线程执行完之后,开采可以执行当前线程
//要等待下载线程结束
download.join();//表示download线程执行完之后,才可以执行当前线程
//判断是否发生异常
if (isFinish){
System.out.println("图片显示完成");
}else{
System.out.println("图片没有下载完成,请稍等");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
download.start();
show.start();
}
}
线程的同步异步:
- 线程同步:多个线程访问同一个资源,其他线程等待当前线程访问资源结束(加锁,线程安全),浪费时间,效率不高
- 线程异步:访问资源的时候,如果有空闲时间,则可以在等待的时间访问资源,实现多线程
如下车票的同步
public class ThreadDemo03 {
public static void main(String[] args) {
TicketDemo tt=new TicketDemo();
Thread t1=new Thread(tt,"火车站窗口");
Thread t2=new Thread(tt,"美团售票窗口");
Thread t3=new Thread(tt,"自动售票窗口");
Thread t4=new Thread(tt,"携程售票窗口");
t1.start();
t2.start();
t3.start();
t4.start();
/*
四个窗口卖票,出现重票(:数重复) 错票(:少数)
为什么会出现这个问题?
三个窗口都在操作车票,当火车站在卖票的时候,卖票的操作没有结束;美团参与进来了
就会出现线程安全问题,
出现问题如何解决
线程同步;
当一个线程进入车票操作的时候,其他线程不允许参与进来,直到当前线程操作结束,才允许其他线程进入
*/
}
}
class TicketDemo implements Runnable{
int ticket=5;
@Override
public void run() {
//同步代码块,上锁
// while (true){
// //当第一个线程票数1,判断票数大于0?还没有对票数进行操作时
// //第二个线程又开始了,票数还是1,判断票数大于0的
// synchronized (this){
// //操作共享数据的代码
// if (ticket>0){
// System.out.println(Thread.currentThread().getName()+"----:"+ticket);
// ticket--;
// }else{
// break;
// }
// }
// }
while (true){
if (show()){
}else{
break;
}
}
}
public synchronized boolean show(){
if (ticket>0){
System.out.println(Thread.currentThread().getName()+"---------"+ticket);
ticket--;
}else {
return false;
}
return true;
}
}
java如何解决线程安全问题
- 同步代码块(上锁)
- 同步方法
同步代码块:
synchronize(同步监视器){
//需要被同步的代码块,
}
同步监视器:任何一个类的对象都可以来充当,俗称锁(多线程必须公用一把锁)
需要被同步的代码块:操作共享数据的代码
同步方法:
将方法声明为同步的,将操作共享数据的代码放入这个方法即可
在上述的车票同步为题:这两个方法都使用了,只是方法一被注释了,使用的是方法二
同步资源的死锁:
- 不同的线程分别占用几个对象需要的同步资源不放弃,都在等待对方放弃自己需要的同步资源,就形成了线程的死锁
注意:出现死锁之后,不会出现异常,也不会出现提示,只是所有的线程都处于阻塞状态无法继续工作,所以我们在使用同步资源的时候,避免出现死锁线程
避免死锁:
- 尽量避免同步的嵌套
- 尽量减少同步资源的定义 (同步资源没了,就不会出现死锁)
- 专门的算法/原则
一个简单死锁代码:
public class ThreadDemo04 {
public static void main(String[] args) {
StringBuffer sb1=new StringBuffer();
StringBuffer sb2=new StringBuffer();
/*
Thread t=new Thread(){
public void run(){
}
};
t.start();
*/
//简写如下:
//死锁
//第一个线程中,先锁sb1,往sb1后追加1,往sb2后追加a
//再锁sb2,往sb1后追加2,往sb2后追加b
new Thread(){
@Override
public void run() {
synchronized (sb1){
sb1.append("1");
sb2.append("a");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (sb2){
sb1.append("2");
sb2.append("b");
//输出
System.out.println(getName()+"---"+sb1);
System.out.println(getName()+"---"+sb2);
}
}
}
}.start();
//第二个线程,先锁sb2,往sb1后追加3,往sb2后追加c
//再锁sb1,往sb1后追加2,往sb2后追加b
new Thread(){
@Override
public void run() {
synchronized (sb2){
sb1.append("3");
sb2.append("c");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (sb1){
sb1.append("4");
sb2.append("d");
//输出
System.out.println(getName()+"---"+sb1);
System.out.println(getName()+"---"+sb2);
}
}
}
}.start();
}
}
今天的分享到此结束了,希望诸位能在此有个不少的收获,如果有错误的,麻烦斧正下,谢谢!
版权声明:本文为Takeit_easy原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。