Thread类
/*
进程:是系统进行资源分配和调用的独立单位,每一个进程都有它自己的内存空间和系统资源。
举例:IDEA, 阿里云盘, wegame, steam
线程:是进程中的单个顺序控制流,是一条执行路径
一个进程如果只有一条执行路径,则称为单线程程序。
一个进程如果有多条执行路径,则称为多线程程序。
java提供了一个类用来描述线程:Thread
线程是程序中执行的线程。
Java虚拟机允许应用程序同时执行多个执行线程。
每个线程都有优先权, 具有较高优先级的线程优先于优先级较低的线程执行
创建线程的方式:实现Runnable接口,借助Thread类创建线程对象和继承Thread类方式
若将来每一个线程执行的逻辑是一样的话,推荐采用实现Runnable接口方式实现多线程
若将来每一个线程执行逻辑不一样的话,推荐采用继承Thread类方式实现多线程
*/
代码案例
创建线程的第二种方式:实现Runnable接口,借助Thread类创建线程对象
若将来每一个线程执行的逻辑是一样的话,推荐采用第二种实现Runnable接口方式实现多线程
若将来每一个线程执行逻辑不一样的话,推荐采用第一种继承Thread类方式实现多线程
class MyThread extends Thread{
public MyThread(String name) {
super(name);
}
@Override
public void run() {
//run方法是将来线程对象启动时要执行的计算逻辑
for(int i=1;i<=200;i++){
System.out.println(getName()+" - "+i);
}
}
}
public class ThreadDemo1 {
public static void main(String[] args) {
//创建一个线程对象
// MyThread t1 = new MyThread();
// MyThread t2 = new MyThread();
MyThread t1 = new MyThread("李刚");
MyThread t2 = new MyThread("钱志强");
//给线程起名字
// 方式1:调用setName()方法起名字
// t1.setName("李刚");
// t2.setName("钱志强");
// 方式2:使用构造方法起名字
// t1.run();
// t2.run();
t1.start(); // 系统分配资源给线程t1,启动线程,t1线程具备了执行的资格,具体等到抢到cpu执行权的时候才会执行
t2.start();
}
}
/*
休眠线程
public static void sleep(long millis)
加入线程:
public final void join()
礼让:
public static void yield()
后台线程:
public final void setDaemon(boolean on)
用户线程:优先级高于守护线程
守护线程【后台线程】:当一个程序没有了用户线程,守护线程也就没有了
中断线程:
public final void stop() 已弃用
public void interrupt()
java所有的线程要想变成运行状态,必须经过抢cpu执行权
*/
线程安全问题
如何判断一个程序是否存在线程安全的问题呢?
三要素,缺一不可:
1、是否存在多线程环境? 是
2、是否存在共享数据/共享变量?是tickets
3、是否存在多条语句操作着共享数据/共享变量? 是
怎么解决?
方案1:同步代码块
synchronized(对象){需要同步的代码;} 这里对象要保证多个线程对象唯一的 传入的是对象的类的class对象
同步方法:锁对象是this
同步静态方法:锁对象是当前类的class文件对象 类.class
方案2:lock锁
// 加锁
lock.lock();{进程语句}
//释放锁
lock.unlock();
synchronized代码案例
lass Window2 implements Runnable{
int tickets = 200;
Object obj = new Object();
@Override
public void run() {
while (true){
synchronized (obj){
if(tickets>0){ // 1
try {
// t1
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("当前 " + Thread.currentThread().getName()+" 正在出售第 "+(tickets--)+" 张票");
}
}
}
}
}
public class SellTicketsDemo2 {
public static void main(String[] args) {
Window2 window2 = new Window2();
Thread t1 = new Thread(window2, "窗口1");
Thread t2 = new Thread(window2, "窗口2");
Thread t3 = new Thread(window2, "窗口3");
t1.start();
t2.start();
t3.start();
}
}
lock锁代码案例
package com.shujia.day18;
import java.util.concurrent.locks.ReentrantLock;
/*
使用lock锁来解决线程安全的问题
*/
class Window4 implements Runnable {
int tickets = 200;
Object obj = new Object();
ReentrantLock lock = new ReentrantLock();
@Override
public void run() {
while (true) {
// 加锁
lock.lock();
if (tickets > 0) { // 1
try {
// t1
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("当前 " + Thread.currentThread().getName() + " 正在出售第 " + (tickets--) + " 张票");
}
//释放锁
lock.unlock();
}
}
}
public class SellTicketsDemo4 {
public static void main(String[] args) {
Window4 window4 = new Window4();
Thread t1 = new Thread(window4, "窗口1");
Thread t2 = new Thread(window4, "窗口2");
Thread t3 = new Thread(window4, "窗口3");
t1.start();
t2.start();
t3.start();
}
}
死锁
public class Locks {
public static final ReentrantLock LOCK1 = new ReentrantLock();
public static final ReentrantLock LOCK2 = new ReentrantLock();
private Locks(){}
}
package com.shujia.day18;
/*
死锁:线程之间存在相互等待的现象
案例:中国人和外国人
前提:中国人吃饭必须要两支筷子,外国人吃饭必须一把刀和一把叉
现在:
中国人:一支筷子和一把刀
外国人:一支筷子和一把叉
*/
class Person extends Thread{
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 DieLock {
public static void main(String[] args) {
Person p1 = new Person(true);
Person p2 = new Person(false);
p1.start();
p2.start();
}
}
等待唤醒
/*
等待唤醒机制:
生产者
消费者
共享数据
测试类
等待唤醒机制:前提是要保证程序是线程安全的
*/
public class WaitNotifyDemo1 {
public static void main(String[] args) {
Student s = new Student();
//创建生产者线程对象
Product product = new Product(s);
//创建消费者线程对象
Consumer consumer = new Consumer(s);
product.start();
consumer.start();
}
}
package com.shujia.day18.bao1;
public class Product extends Thread{
Student s;
int i =0;
public Product(Student s) {
this.s = s;
}
@Override
public void run() {
// Student s = new Student();
while (true){
synchronized (s){
//作为生产者,在生产数据之前,应该先检查一下数据有没有被消费
//如果没有被消费,就等待消费者消费
if(s.flag){
//等待 锁对象调用方法等待
try {
s.wait(); // 程序走到这一步,发生阻塞,直到锁对象再次在程序中被调用了notify()方法
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if(i%2==0){
s.setName("李刚");
s.setAge(18);
}else {
s.setName("钱志强");
s.setAge(10);
}
// 生产完数据后,通知消费者来消费数据
// 由锁对象来通知
s.notify();
s.setFlag(true);
i++;
}
}
}
}
package com.shujia.day18.bao1;
public class Consumer extends Thread{
Student s;
public Consumer(Student s) {
this.s = s;
}
@Override
public void run() {
// Student s = new Student();
while (true){
synchronized (s){
//消费者在消费数据之前,应该先看一看数据有没有产生【flag是否是true】
//若没有数据产生,等待生产者生产数据
if(!s.flag){
try {
s.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(s.getName()+"-"+s.getAge());
//消费者消费完数据后,通知生产者生产数据
s.notify();
s.setFlag(false);
}
}
}
}
标签:Thread,void,public,线程,new,day18,class
From: https://www.cnblogs.com/flxf/p/18470359