1.概述
多线程:充分的利用计算机资源,同时执行不同的操作
1.计算机的操作系统。进程和线程
2.使用java来完成多线程的编码
3.线程中的常方法
4.线程同步(重点)
5.死锁
6.生产者消费者模型。异步
2.操作系统的简介
操作系统:本质就是一个运行在一堆硬件上的巨型软件
存在的意义:帮助上层应用程序屏蔽掉硬件的丑陋的接口
操作系统的发展史:
1.手工操作
2.批处理系统
3.多道批处理
4.分时系统
5.实时系统
进程和线程:
- 进程:正在执行的程序,其实就是一块内存区域,内部存储这程序的资源
- 线程:程序被CPU调度的最小单位,
3.java多线程
1继承Thread类,重写run方法
2.实现Runnable接口,实现run方法
必须:run(),start()
run():线程执行的时候执行的代码
start():启动一个线程
package Thread.MyThread;
public class myThread extends Thread {
@Override
public void run() {
//要把子线程执行的内容写在run里
for (int i = 0; i<1000;i++){
System.out.println("我是子线程:"+i);
}
}
}
package Thread.MyThread;
public class Test {
public static void main(String[] args) {//主线程
//1.创建线程对象
myThread mt = new myThread();
//2.调用start()方法启动一个线程
// mt.run();//方法的调用,不是启动线程
mt.start();//继承自Thread类,启动一个线程-》子线程-》自动执行run()方法
for (int i = 0; i<1000;i++){
System.out.println(">>>>>>>我是主线程"+i);
}
}
}
package Thread.MyThread;
public class MyRunnable implements Runnable {
@Override
public void run() {
for (int i = 0; i<1000;i++){
System.out.println("我是子线程:"+i);
}
}
}
package Thread.MyThread;
public class Test1 {
public static void main(String[] args) {
//1.先创建Runnable的对象
Runnable r = new MyRunnable();
Thread t = new Thread(r);
t.start();
for (int i = 0; i<1000;i++){
System.out.println("主线程:"+i);
}
}
}
4.线程相关操作
setPriority()设置优先级
1-10.5
package Thread.Prioity;
public class MyThread extends Thread{
public MyThread(String name){
super.setName(name);//设置线程的名字
}
@Override
public void run() {
for (int i = 0; i<500;i++){
System.out.println(super.getName()+"==》"+i);
}
}
}
package Thread.Prioity;
public class Test {
public static void main(String[] args) {
MyThread mt1 = new MyThread("A线程");
MyThread mt2 = new MyThread("B线程");
mt2.setPriority(10);//有优先级,但不意味着独占cpu
mt1.setPriority(4);//优先级低,但是不代表不执行
mt1.start();
mt2.start();
}
}
sleep(毫秒)睡眠(重点)
package Thread.Sleep;
import java.text.SimpleDateFormat;
import java.util.Date;
public class MyThread extends Thread {
@Override
public void run() {
while (true){
//让子线程不断显示系统时间
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date d = new Date();
System.out.println(sdf.format(d));
try {
Thread.sleep(1000);//睡眠1000毫秒----》1秒
} catch (InterruptedException e) {
}
}
}
public static void main(String[] args) {
MyThread mt = new MyThread();
mt.start();
}
}
每隔xxx时间去执行xxx工作
join()让主线程等待这个子线程执行完毕
package Thread.join;
public class MyThread extends Thread{
@Override
public void run() {
for (int i = 0; i<1000;i++){
System.out.println("子线程:"+i);
}
}
}
package Thread.join;
public class Test {
public static void main(String[] args) {
MyThread mt = new MyThread();
mt.start();
for (int i = 0; i<100;i++){
System.out.println("主线程:"+i);
}
try {
mt.join();//会让主线程等待子线程执行完毕,再继续执行
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
}
System.out.println("吼吼吼");
}
}
yield()让出CPU,让别人执行一下
package Thread.yield;
public class MyThread extends Thread{
public MyThread(String name){
super.setName(name);
}
@Override
public void run() {
for(int i = 0;i<100;i++){
if (i%10 ==0){
Thread.yield();
}
System.out.println(super.getName()+":"+i);
}
}
}
package Thread.yield;
public class Test {
public static void main(String[] args) {
MyThread mt1 = new MyThread("A线程");
MyThread mt2 = new MyThread("B线程");
mt1.start();
mt2.start();
}
}
interrupt()打断正在睡眠中的线程
package Thread.inter;
public class Mythread extends Thread {
@Override
public void run() {
System.out.println("我要睡觉了");
try {
Thread.sleep(100000000);
} catch (InterruptedException e) {
System.out.println("为什么不让睡了,醒了");
}
System.out.println("工作");
}
}
package Thread.inter;
import Thread.yield.MyThread;
public class Test {
public static void main(String[] args) {
Mythread MT =new Mythread();
MT.start();
for (int i = 0;i<100;i++){
System.out.println(i);
}
MT.interrupt();//打断正在睡眠中的子线程
}
}
5.线程同步
线程同步:当多个线程共享一个资源的时候,我们可以在某一个线程访问到这个资源的时候,把这个资源暂时封锁,等待执行结束,释放这个锁,其他线程才可以进行操作,线程同步
总结:等待其他线程释放锁,让线程更加的安全
1.在方法声明上添加一个synchronized关键字
2.在方法内部使用synchronized(){}语句块对特定的对象上锁
3.手动上锁—》用的最少’
StringBuffer(有锁)和StringBuilder(无锁)
package Thread.sync;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Account {
private double balance;//账户的钱
private Lock lock = new ReentrantLock();//创建一个锁
public Account(double balance){
this.balance = balance;
}
public void getMoney(){//一旦进入到该方法。瞬间锁定acc
lock.lock();//上锁
if (this.balance <= 0) {
System.out.println("没钱了.");
return;//回去
}
System.out.println("我要取钱了,目前还剩下:" + this.balance);
this.balance -= 1000;
System.out.println("取完了,还剩:"+this.balance);
lock.unlock();//释放这个锁
}
}
package Thread.sync;
public class GetMoneyThread extends Thread {
private Account acc;
//传进去
public GetMoneyThread(Account acc){
this.acc =acc;
}
@Override
public void run() {
acc.getMoney();
}
}
package Thread.sync;
public class Test {
public static void main(String[] args) {
Account acc = new Account(1000);
GetMoneyThread atm = new GetMoneyThread(acc);
GetMoneyThread table = new GetMoneyThread(acc);
atm.start();
table.start();
}
}
6.死锁
使用synchronized的时候一定要格外的注意,有没有互相调用的方法被锁定,慎重使用synchronized。
package Thread.dead;
public class DeadLock1 extends Thread {
@Override
public void run() {
synchronized (ResourseObject.obj1){
System.out.println("锁定第一个资源");
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (ResourseObject.obj2){
System.out.println("锁定第二个资源");
System.out.println("锁定完毕");
}
}
}
}
package Thread.dead;
import javax.jws.soap.SOAPBinding;
public class DeadLock2 extends Thread{
@Override
public void run() {
synchronized (ResourseObject.obj2){
System.out.println("锁定资源2");
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (ResourseObject.obj1){
System.out.println("锁定资源1");
System.out.println("执行完毕");
}
}
}
}
package Thread.dead;
public class ResourseObject {
public static Object obj1 = new Object();
public static Object obj2 = new Object();
}
package Thread.dead;
public class Test {
public static void main(String[] args) {
DeadLock1 dl1 = new DeadLock1();
DeadLock2 dl2 = new DeadLock2();
dl1.start();
dl2.start();
}
}
7.线程周期
8.生产者消费者
先读取视频,对视频内容进行鉴定-》发现违法内容,把该视频进行标记-》发送公安局
异步,左边不用等右边,右边不用等左边
生产者消费者模型:读取视频这一方被称为生产者,产品就是(小视频)右边发送给公安局就是消费者
Queue:队列。BlockingQueue阻塞队列,当队列中没有数据的时候,需要拿数据,队列会将程序阻塞,阻塞到有数据,队列继续工作。
package Thread.yellow;
/**
* 产品,视频
*/
public class Video {
private String name;
public Video(String name){
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
package Thread.yellow;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.atomic.AtomicInteger;
public class ReadVideoThread extends Thread {
private static AtomicInteger i = new AtomicInteger();
//准备能装视频的缓冲区(队列)
private BlockingQueue<Video> videoQueue;
public ReadVideoThread(BlockingQueue<Video> videoQueue){
this.videoQueue = videoQueue;
}
@Override
public void run() {
while (true){
String name = "苍老师"+i.incrementAndGet();
Video v = new Video(name);//相当于i++
try {
videoQueue.put(v);//添加数据
Thread.sleep(200);//让两个视频的执行效率不一样
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发现了一个视频"+name);
}
}
}
package Thread.yellow;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.atomic.AtomicInteger;
public class SendYelloThread extends Thread {
private static AtomicInteger i = new AtomicInteger();
private BlockingQueue<Video> videoQueue;
public SendYelloThread(BlockingQueue<Video> videoQueue){
this.videoQueue = videoQueue;
}
@Override
public void run() {
while (true){
try {
Video video = videoQueue.take();
System.out.println("我是发送的地方,我发现了一个视频"+video.getName());
Thread.sleep(150);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
package Thread.yellow;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingDeque;
public class Test {
public static void main(String[] args) {
BlockingQueue<Video> videos = new LinkedBlockingDeque<Video>();
ReadVideoThread rvt1 = new ReadVideoThread(videos);
ReadVideoThread rvt2 = new ReadVideoThread(videos);
ReadVideoThread rvt3 = new ReadVideoThread(videos);
SendYelloThread syt1 = new SendYelloThread(videos);
SendYelloThread syt2 = new SendYelloThread(videos);
rvt1.start();
rvt2.start();
rvt3.start();
syt1.start();
syt2.start();
}
}
练习
package Thread.HomeWork;
import java.util.List;
import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;
public class TableThread extends Thread {
private List<Ticket>ticketList;
private static AtomicInteger i = new AtomicInteger();
public TableThread(List<Ticket> ticketList,String name){
this.ticketList = ticketList;
this.setName(name);//设置名字
}
@Override
public void run() {
while (true){
if(i.get() + 4 < ticketList.size()){
try {
Thread.sleep(new Random().nextInt(150));
} catch (InterruptedException e) {
e.printStackTrace();
}
Ticket t = ticketList.get(i.incrementAndGet());//i++
System.out.println(this.getName()+"卖出:"+t.getName());//打印车票信息
}else{
System.out.println("卖完了");
break;
}
}
}
}
package Thread.HomeWork;
public class Ticket {
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Ticket(int id, String name){
this.id = id;
this.name = name;
}
}
package Thread.HomeWork;
import java.util.ArrayList;
import java.util.List;
public class Test {
public static void main(String[] args) {
List<Ticket>ticketList = new ArrayList<Ticket>();
for (int i = 0; i<1000;i++){
Ticket t = new Ticket(i,"火车票"+i);
ticketList.add(t);
}
//创建窗口
TableThread tt1 = new TableThread(ticketList,"窗口一");
TableThread tt2 = new TableThread(ticketList,"窗口二");
TableThread tt3 = new TableThread(ticketList,"窗口三");
TableThread tt4 = new TableThread(ticketList,"窗口四");
tt1.start();
tt2.start();
tt3.start();
tt4.start();
}
}