多线程:
进程:
正在运行的程序,是系统进行资源分配和调用的独立单位。
每一个进程都有它自己的内存空间和系统资源。
理解:一个正在运行的软件
线程:
是进程中的单个顺序控制流,是一条执行路径
一个进程如果只有一条执行路径,则称为单线程程序。
一个进程如果有多条执行路径,则称为多线程程序。
举例:阿里云盘(进程)中多个同时进行的任务,每一个任务可以看作一个线程
1、如何创建一个线程对象呢?
a. 自定义线程类继承Thread类,重写run方法
b. 自定义线程类实现Runnable接口,实现run方法
2、如何启动一个线程呢?
调用start()方法启动
Thread无参构造方法
Thread() 分配一个新的 Thread对象。
注意:
1、启动一个线程的时候,若直接调用run方法,仅仅是普通的对象调用方法,按照自上而下的顺序执行,底层不会额外的创建一个线程再执行
2、从执行的结果上来看,java线程之间是抢占式执行的,谁先抢到cpu执行权谁就先执行
3、每次运行的结果顺序不可预测的,完全随机的
4、每个线程都有优先权。 具有较高优先级的线程优先于优先级较低的线程执行。只是优先级高的先执行的概率大一点,并不代表一定先执行,完全是随机。
Thread类中的成员方法:
1、public final String getName() 获取线程对象的名字
2、设置线程对象名字的方式:
a. 通过父类的有参构造方法,在创建线程对象的时候设置名字
b. 线程对象调用setName(String name)方法,给线程对象设置名字
3、获取线程的等级
getPriority() 默认优先级都是5
4、设置线程优先级,setPriority(int i),在启动之前设置 [1,10]
注意不是优先级高的一定先执行,只是可能性变高了。
Thread中sleep()、stop()、join()、yield()、setDaemon()、wait(),notify()的方法使用:
sleep()的使用:线程休眠
线程控制:休眠线程
当线程处于休眠状态的时候,该线程就没有cpu执行权了,若这时还有其他的线程,会被抢走cpu执行权。
代码如下:
class SleepThread extends Thread {
@Override
public void run() {
System.out.println(getName() + " 睡着了。。。。");
try {
Thread.sleep(5000); // 在哪个方法中调用,就是调用该方法的线程对象进行休眠
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(getName()+" 睡醒了。。。。");
}
}
public class ThreadSleepDemo1 {
public static void main(String[] args) {
SleepThread t1 = new SleepThread();
t1.setName("光头强");
t1.start();
}
}
stop()的使用:线程中断
class StopThread extends Thread {
@Override
public void run() {
System.out.println(getName() + " 睡着了。。。。");
try {
Thread.sleep(5000); // 在哪个方法中调用,就是调用该方法的线程对象进行休眠
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(getName()+" 睡醒了。。。。");
}
}
public class ThreadStopDemo1 {
public static void main(String[] args) {
StopThread t1 = new StopThread();
t1.setName("熊大");
t1.start();
try {
Thread.sleep(2000);
// t1.stop();
t1.interrupt();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
join()的使用:线程加入
class JoinThread extends Thread {
@Override
public void run() {
for (int i = 1; i <= 10; i++) {
System.out.println(getName() + " - " + i);
}
}
}
public class ThreadJoinDemo1 {
public static void main(String[] args) {
JoinThread t1 = new JoinThread();
JoinThread t2 = new JoinThread();
JoinThread t3 = new JoinThread();
t1.setName("光头强");
t2.setName("熊大");
t3.setName("熊二");
t1.start();
try {
t1.join(); // 其他线程等待该线程执行结束,其他线程之间会进行抢占式执行
} catch (InterruptedException e) {
e.printStackTrace();
}
t2.start();
t3.start();
}
}
yield()的使用:线程礼让
只是让结果看起来更加均匀一些,并不是我们日常生活中理解的完全谦让
礼让线程
yield()只是为了运行结果看起来均匀一些
class YieldThread extends Thread{
@Override
public void run() {
for(int i=1;i<200;i++){
System.out.println(getName()+" - "+i);
Thread.yield();
}
}
}
public class ThreadYieldDemo1 {
public static void main(String[] args) {
YieldThread t1 = new YieldThread();
YieldThread t2 = new YieldThread();
t1.setName("民哥");
t2.setName("原神哥");
t1.start();
t2.start();
}
}
setDaemon()后台线程:
用户线程
守护线程
在启动之前,设置一下,若一个进程中没有用户线程,守护线程也没有必要存在。
class DaemonThread extends Thread {
@Override
public void run() {
for (int i = 1; i <= 200; i++) {
System.out.println(getName() + " - " + i);
}
}
}
public class ThreadDaemonDemo1 {
public static void main(String[] args) {
DaemonThread t1 = new DaemonThread();
DaemonThread t2 = new DaemonThread();
DaemonThread t3 = new DaemonThread();
t1.setName("刘备");
t2.setName("关羽");
t3.setName("张飞");
t2.setDaemon(true);
t3.setDaemon(true);
t1.start();
t2.start();
t3.start();
}
}
wait()和notify()的使用:可用于生产者和消费者模型中,wait()就是等待,等待某个程序的完成后,再进行解锁notify(),再让其他程序运行,wait()等待期间,属于程序阻塞
使用Runnable的方式实现:售票问题(SellTickets)
为了模拟更加真实的售票情况,我们加入延迟
问题:
我们加入了延迟之后,发现
a. 有重复售卖同一张票的情况(原因1)
b. 还出现了一个不该出现的票数据,比如第0张票,第-1张票(原因2)
原因:
1. cpu小小的时间片,足以让程序执行很多次
2. 线程的执行具有随机性,且是抢占式执行的
现象:线程不安全的现象
如何判断一个程序是否存在线程不安全的现象呢?
三要素(同时满足):
1、是否存在多线程环境?
2、是否存在共享数据?
3、是否存在多条语句操作着共享数据?
如何解决线程不安全的现象?
1、同步代码块
2、lock锁
解决方案1:加入同步代码块
synchronized(对象){
操作共享数据的代码
}
这里的对象,可以是任意一个new出来的对象,但是要保证多个线程之间是同一个对象。
synchronized的使用:
1、同步代码块 - 锁对象 - 任意一个对象,前提是多个线程对象共享一个
2、同步方法 - 锁对象 - this
3、同静态方法 - 锁对象 - 当前类的class文件对象
解决方案2:lock锁,利用ReentrantLock类创建锁对象,要求多个线程对象共享一个
不需要考虑锁对象是谁了。
同步代码块1:锁任意对象--Object
class Window implements Runnable{
private static int tickets = 100;
private Object object = new Object();
@Override
public void run() {
while (true){
synchronized (object){
if(tickets>0){
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+" 正在出售第 "+(tickets--)+" 张票......");
}
}
}
}
}
public class SellTicketDemo1 {
public static void main(String[] args) {
Window window = new Window();
Thread w1 = new Thread(window,"窗口1");
Thread w2 = new Thread(window,"窗口2");
Thread w3 = new Thread(window,"窗口3");
w1.start();
w2.start();
w3.start();
}
}
同步代码块2:锁对象--this
class Window implements Runnable {
private static int tickets = 100;
// private Object object = new Object();
private int i = 0;
@Override
public void run() {
while (true) {
if (i % 2 == 0) {
synchronized (this) {
if (tickets > 0) {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " 正在出售第 " + (tickets--) + " 张票......");
}
}
} else {
sellTicket();
}
i++;
}
}
//同步方法,将synchronized在方法定义上出现
// public synchronized void sellTicket() {
// if (tickets > 0) {
// try {
// Thread.sleep(50);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// System.out.println(Thread.currentThread().getName() + " 正在出售第 " + (tickets--) + " 张票......");
// }
// }
public static synchronized void sellTicket() {
if (tickets > 0) {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " 正在出售第 " + (tickets--) + " 张票......");
}
}
}
public class SellTicketDemo1 {
public static void main(String[] args) {
Window window = new Window();
Thread w1 = new Thread(window, "窗口1");
Thread w2 = new Thread(window, "窗口2");
Thread w3 = new Thread(window, "窗口3");
w1.start();
w2.start();
w3.start();
}
}
同步代码块3:锁对象--当前类的class文件对象
class Window implements Runnable {
private static int tickets = 100;
// private Object object = new Object();
private int i = 0;
@Override
public void run() {
while (true) {
if (i % 2 == 0) {
synchronized (Window.class) {
if (tickets > 0) {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " 正在出售第 " + (tickets--) + " 张票......");
}
}
} else {
sellTicket();
}
i++;
}
}
//同步方法,将synchronized在方法定义上出现
// public synchronized void sellTicket() {
// if (tickets > 0) {
// try {
// Thread.sleep(50);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// System.out.println(Thread.currentThread().getName() + " 正在出售第 " + (tickets--) + " 张票......");
// }
// }
public static synchronized void sellTicket() {
if (tickets > 0) {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " 正在出售第 " + (tickets--) + " 张票......");
}
}
}
public class SellTicketDemo1 {
public static void main(String[] args) {
Window window = new Window();
Thread w1 = new Thread(window, "窗口1");
Thread w2 = new Thread(window, "窗口2");
Thread w3 = new Thread(window, "窗口3");
w1.start();
w2.start();
w3.start();
}
}
lock锁:不用考虑锁对象
class Window implements Runnable {
private static int tickets = 100;
// private Object object = new Object();
private ReentrantLock lock = new ReentrantLock();
@Override
public void run() {
while (true) {
lock.lock(); // 加锁
if (tickets > 0) {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " 正在出售第 " + (tickets--) + " 张票......");
}
lock.unlock(); // 释放锁
}
}
}
public class SellTicketDemo1 {
public static void main(String[] args) {
Window window = new Window();
Thread w1 = new Thread(window, "窗口1");
Thread w2 = new Thread(window, "窗口2");
Thread w3 = new Thread(window, "窗口3");
w1.start();
w2.start();
w3.start();
}
}
死锁情况:
分两个类:Locks对象类,测试类, 死锁的问题:线程之间存在相互等待的现象
Locks对象类:
import java.util.concurrent.locks.ReentrantLock;
public class Locks {
private Locks(){}
public static final ReentrantLock lock1 = new ReentrantLock();
public static final ReentrantLock lock2 = new ReentrantLock();
}
测试类:
class Person extends Thread{
private boolean flag;
public Person(boolean flag) {
this.flag = flag;
}
@Override
public void run() {
if(flag){
synchronized (Locks.lock1){
System.out.println("if lock1");
// p1
synchronized (Locks.lock2){
System.out.println("if lock2");
}
}
}else {
synchronized (Locks.lock2){
System.out.println("else lock2");
// p2
synchronized (Locks.lock1){
System.out.println("else lock1");
}
}
}
}
}
public class DieLockDemo {
public static void main(String[] args) {
Person p1 = new Person(true);
Person p2 = new Person(false);
p1.start();
p2.start();
}
}
标签:Thread,lock,void,class,线程,new,public
From: https://blog.csdn.net/ABU009/article/details/141334473