1.守护线程

线程分为守护线程和用户线程  : daemon thread and non-daemon thread

虚拟机必须等待用户线程执行完毕,但无需等待守护线程执行完毕。

守护线程举例:垃圾回收线程,监控内存线程。

setDaemon(true):默认为false,默认为用户线程
public class D19 { public static void main(String[] args) { Thread thread =
new Thread(new A1()); thread.setDaemon(true); thread.start(); new Thread(new
A2()).start(); } } class A1 implements Runnable{ @Override public void run() {
while(true){ System.out.println("This is a daemon thread."); } } } class A2
implements Runnable{ @Override public void run() { for (int i = 0; i < 100;
i++) { System.out.println("This is a non-daemon thread."); }
System.out.println("The non-daemon thread has finished."); } }
A1并没有设置停止条件,但因为将它设置为了守护线程,所以程序可以正常结束。

2.线程同步

并发:多个线程操作一个对象

当多个线程操作同一个对象,并且有线程想要修改该对象时,就会出现线程同步的问题。

线程同步是一种等待机制,多个线程进入该对象的等待池形成队列,等待前一个线程使用完毕,下一个线程再使用。

使用线程和锁来保证线程同步的安全性。

锁机制:当一个线程获得锁,独占资源,其他线程必须等待,直到该线程使用完毕,释放锁。

问题:

* 等待该资源的对象挂起
* 加锁,释放锁导致更多的开销:上下文切换,调度延时
* 优先级倒置

3.运用synchronized关键字解决线程并发造成的不安全问题

1)synchronized关键字修饰方法,默认锁的是该方法的对象

使用前:
import org.omg.CORBA.TIMEOUT; public class D20 { public static void
main(String[] args) { Ticket ticket = new Ticket(); new Thread(ticket).start();
new Thread(ticket).start(); new Thread(ticket).start(); new
Thread(ticket).start(); } } class Ticket implements Runnable{ int ticketNum =
20; boolean flag = true; @Override public void run() { while(flag){ try {
buy(); } catch (InterruptedException e) { throw new RuntimeException(e); } } }
public void buy() throws InterruptedException { if(ticketNum<=0){ flag = false;
return; } Thread.sleep(100);
System.out.println(Thread.currentThread().getName()+" buy ticket: " +
ticketNum--); } }
不安全结果:多个对象取到相同的票

 加入synchronized关键字
import org.omg.CORBA.TIMEOUT; public class D20 { public static void
main(String[] args) { Ticket ticket = new Ticket(); new Thread(ticket).start();
new Thread(ticket).start(); new Thread(ticket).start(); new
Thread(ticket).start(); } } class Ticket implements Runnable{ int ticketNum =
20; boolean flag = true; @Override public void run() { while(flag){ try {
buy(); } catch (InterruptedException e) { throw new RuntimeException(e); } } }
public synchronized void buy() throws InterruptedException { if(ticketNum<=0){
flag = false; return; } Thread.sleep(100);
System.out.println(Thread.currentThread().getName()+" buy ticket: " +
ticketNum--); } }
结果:不再出现取到同一张票的问题

2)用synchronized同步块

synchronized(Obj){ }

Obj为同步监视器,锁定代码块,同一时刻下只有一个线程访问该代码块

当synchronized修饰方法时,同步监视器默认为该方法的对象,也就是this

使用前:
import java.util.ArrayList; import java.util.List; public class D21 { public
static void main(String[] args) throws InterruptedException { List<String> list
= new ArrayList<String>(); for(int i=0;i<10000;i++){ new Thread(()->{
list.add(Thread.currentThread().getName()); } ).start(); } Thread.sleep(100);
System.out.println(list.size()); } }
不安全结果:多个线程向同一个地址写入数据,导致list的size不足10000

加入synchronized修饰代码块
import java.util.ArrayList; import java.util.List; public class D21 { public
static void main(String[] args) throws InterruptedException { List<String> list
= new ArrayList<String>(); for(int i=0;i<10000;i++){ new Thread(()->{
synchronized (list) { list.add(Thread.currentThread().getName()); } }
).start(); } Thread.sleep(100); System.out.println(list.size()); } }
 结果:

java中有线程安全的ArrayList: CopyOnWriteArrayList
import java.util.concurrent.CopyOnWriteArrayList; public class D22 { public
static void main(String[] args) { CopyOnWriteArrayList<String> list = new
CopyOnWriteArrayList<>(); for (int i = 0; i < 10000; i++) { new Thread( ()->{
list.add(Thread.currentThread().getName()); } ).start(); } try {
Thread.sleep(1000); } catch (InterruptedException e) { throw new
RuntimeException(e); } System.out.println(list.size()); } }

技术
下载桌面版
GitHub
Gitee
SourceForge
百度网盘(提取码:draw)
云服务器优惠
华为云优惠券
腾讯云优惠券
阿里云优惠券
Vultr优惠券
站点信息
问题反馈
邮箱:[email protected]
吐槽一下
QQ群:766591547
关注微信