程序地带

多线程


多线程
多任务
现实中看起来时多个任务在做,其实本质上我们的大脑在同一时间依旧只组做了一件事
Process与Thread
程序:指令和数据的有序集合,其本身没有任何运行含义。是一个静态的概念。进程:执行程序的一次执行过程,它是一个动态的概念。是系统资源分配的单位通常一个进程中可以包含若干个线程,线程是cpu调度和执行的单位

注意:很多多线程是模拟出来的,真正的多线程是指有多个cpu,即多核,,如果是模拟出来的多线程,即在一个cpu的情况下,在同一个时间点,cpu只能执行一个代码,因为切换的很快。


线程就是独立的执行路径在程序运行时,即使没有自己创建线程,后台也会有多个线程,例如主线程,gc线程main()称之为主线程,为系统的入口,用于执行整个程序;在一个进程中开辟了多个线程,线程的运行由调度器安排调度,调度器是与操作系统紧密相关的,先后顺序是不能人为干预的。对同一份资源操作时,会存在资源抢夺问题,需要加入并发控制。线程会带来额外的开销,如cpu调度时间,并发控制开销每个线程在自己的工作内存交互,内存控制不当会造成数据不一致
三种创建方式
继承Thread类
package oop;
//创建线程方式一:继承Thread类,重写run()方法,调用start开启线程
public class Day37 extends Thread{
@Override
public void run() {
System.out.println("hello");
for (int i = 0; i <20 ; i++) {
System.out.println(i+"run");
}
//run方法线程体
}
public static void main(String[] args) {
Day37 d=new Day37();
d.start();
for (int i = 0; i <1000 ; i++) {
System.out.println(i+"main");
}
}
}

在这里插入图片描述 //使用start()主线程和其他线程同时执行


案例:多线程下载图片
commons-io.jar包下载地址

http://commons.apache.org/proper/commons-io/download_io.cgi


[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-00OGw6Oy-1610722248171)(C:Users15512AppDataRoamingTypora	ypora-user-imagesimage-20210113190423714.png)] 在这里插入图片描述


新建lib包->将commons-io-2.8.0.jar导入至ib包中-》添加库
package test;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
//练习Thread,实现多线程同步下载图片
public class TestThread extends Thread {
private String url;
private String name;
public TestThread(String url, String name) {
this.url = url;
this.name = name;
}
@Override
public void run() {
WebDownloader webd=new WebDownloader();
webd.downloader(url,name);
System.out.println("下载了文件名为"+name);
}
public static void main(String[] args) {
TestThread t1=new TestThread("https://image.so.com/view?src=360pic_strong&z=1&i=0&cmg=15484592.1015559986774803200.1600778740583.7642&q=%E7%BE%8E%E5%A5%B3&correct=%E7%BE%8E%E5%A5%B3&ancestor=list&cmsid=6789f5a01d342564e23ba1babf09e387&cmras=1&cn=0&gn=0&kn=50&crn=0&bxn=0&fsn=110&cuben=0&pornn=0&manun=50&adstar=0&clw=234#id=b4af51a0fc9827cda1c5a45db2fd2bb6&currsn=0&ps=135&pc=135","C:\Users\15512\Desktop\gire1.jpg");
TestThread t2=new TestThread("https://image.so.com/view?src=360pic_strong&z=1&i=0&cmg=15484592.1015559986774803200.1600778740583.7642&q=%E7%BE%8E%E5%A5%B3&correct=%E7%BE%8E%E5%A5%B3&ancestor=list&cmsid=6789f5a01d342564e23ba1babf09e387&cmras=1&cn=0&gn=0&kn=50&crn=0&bxn=0&fsn=110&cuben=0&pornn=0&manun=50&adstar=0&clw=234#id=6d36f2b4b3b5304b0fb178c2c8cce1bb&currsn=0&ps=135&pc=135","C:\Users\15512\Desktop\gire2.jpg");
TestThread t3=new TestThread("https://image.so.com/view?src=360pic_strong&z=1&i=0&cmg=15484592.1015559986774803200.1600778740583.7642&q=%E7%BE%8E%E5%A5%B3&correct=%E7%BE%8E%E5%A5%B3&ancestor=list&cmsid=6789f5a01d342564e23ba1babf09e387&cmras=1&cn=0&gn=0&kn=50&crn=0&bxn=0&fsn=110&cuben=0&pornn=0&manun=50&adstar=0&clw=234#id=225d60ede9ed7acecc3d86e31ff27995&currsn=0&ps=135&pc=135","C:\Users\15512\Desktop\gire3.jpg");
t1.start();
t2.start();
t3.start();
}
}
//下载器
class WebDownloader{
public void downloader(String url,String name){
try {
FileUtils.copyURLToFile(new URL(url),new File(name));
} catch (IOException e) {
System.out.println("IO异常,downloader");
}
}
}
实现Runnable
package test;
public class TestThread2 implements Runnable{
@Override
public void run() {
for (int i = 0; i <20 ; i++) {
System.out.println(i+"run");
}
}
public static void main(String[] args) {
TestThread2 test1=new TestThread2();
Thread t1=new Thread(test1);
Thread t2=new Thread(test1);
Thread t3=new Thread(test1);
Thread t4=new Thread(test1);
t1.start();
for (int i = 0; i <1000 ; i++) {
System.out.println(i+"main");
}
}
}
龟兔赛跑sleep
package test;
public class gtRun implements Runnable{
static boolean f=true;
@Override
public void run() {
int g=0;
int t=0;
while(f) {
if (Thread.currentThread().getName().equals("兔子")) {
if (t==10){
try {
Thread.sleep(1111);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
t++;
if (t==40){
System.out.println("twin");
f=false;
}
} else {
try {
Thread.sleep(0);
} catch (InterruptedException e) {
e.printStackTrace();
}
g++;
if (g==40){
System.out.println("gwin");
f=false;
}
}
}
}
public static void main(String[] args) {
gtRun gt=new gtRun();
Thread g=new Thread(gt,"乌龟");
Thread t=new Thread(gt,"兔子");
g.start();
t.start();
}
}
静态代理
package test;
public class TestTread {
public static void main(String[] args) {
new Thread( ()-> System.out.println("I love You")).start();
new Company(new You()).HappyMarry();
/*Company t=new Company(new You());
t.HappyMarry();*/
}
}
interface Marry{
void HappyMarry();
}
class You implements Marry{
@Override
public void HappyMarry() {
System.out.println("我要结婚了我很开心");
}
}
class Company implements Marry{
private Marry t;
public Company(You t) {
this.t = t;
}
@Override
public void HappyMarry() {
brefor();
t.HappyMarry();
after();
}
private void after() {
System.out.println("请付钱");
}
private void brefor() {
System.out.println("求婚");
}
}
//I love You
//求婚
//我要结婚了我很开心
//请付钱
真实对象和代理对象都要实现同一个接口代理对象要代理真实对象好处
代理对象可以做很多真实对象做不了的事情真实对象专注于自己的事情
Lamda表达式
避免匿名内部类定义过多实质属于函数式编程的概念
函数式接口定义
任何接口,如果只包含唯一一个抽象方法,那么它就是一个函数式接口对于函数式接口,我们就可以用Lanbda表达式来创建该接口的对象
package test;
public class TestThread3 {
static class Test2 implements Marry1{
// 静态内部类
@Override
public void Hello() {
System.out.println("静态内部类Test2");
}
}
public static void main(String[] args) {
new Test1().Hello();
new Test2().Hello();
// 局部内部类
class Test3 implements Marry1{
@Override
public void Hello() {
System.out.println("静态内部类Test3");
}
}
new Test3().Hello();
// 匿名内部类 没有类的名称,必须借助接口或者父类
new Marry1() {
@Override
public void Hello() {
System.out.println("new Marry1()");
}
};//就是一个语句了
Marry1 t;
t=()->{
System.out.println("Lambda表达式");
};
t.Hello();
}
}
interface Marry1{
void Hello();
}
//实现类
class Test1 implements Marry1 {
@Override
public void Hello() {
System.out.println("实现类Test1");
}
}
/*实现类Test1
静态内部类Test2
静态内部类Test3
Lambda表达式*/
线程的状态

截取与b站的狂神


线程礼让
当前正在执行的线程暂停,但不阻塞。将线程从运行状态转为就绪状态让cpu重新调度,礼让不一定成功!看cpu心情
package test;
public class TestTreadYield implements Runnable{
TestTreadYield t1=new TestTreadYield();
Thread td1=new Thread(t1);
Thread td2=new Thread(t1);
td1.start();
td2.start();
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"线程进入");
Thread.yield();
System.out.println(Thread.currentThread().getName()+"线程暂停");
}
}
/*
Thread-1线程进入
Thread-0线程进入
Thread-0线程暂停
Thread-1线程暂停*/
线程强制执行
join合并线程,待此线程执行完后,再执行其他线程,其他线程阻塞
package test;
public class TestThreadJoin implements Runnable{
@Override
public void run() {
for (int i = 0; i <100 ; i++)
System.out.println("run");
}
public static void main(String[] args) {
TestThreadJoin R=new TestThreadJoin();
Thread t1=new Thread(R);
t1.start();
for (int i = 0; i <50 ; i++) {
System.out.println("main"+i);
if (i == 1) {
try {
t1.join();
} catch (InterruptedException e) {
System.out.println("xxcc");
}
}
}
}
}
线程优先级
package test;
public class TestThread4 implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());
}
public static void main(String[] args) {
System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());
TestThread4 r=new TestThread4();
Thread t1=new Thread(r,"a");
Thread t2=new Thread(r,"b");
Thread t3=new Thread(r,"c");
Thread t4=new Thread(r,"d");
Thread t5=new Thread(r,"e");
Thread t6=new Thread(r,"f");
t1.setPriority(Thread.MAX_PRIORITY);
t2.setPriority(1);
t3.setPriority(2);
t4.setPriority(3);
t5.setPriority(4);
t6.setPriority(9);
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
t6.start();
}
}
/*main-->5
a-->10
d-->3
b-->1
f-->9
c-->2
e-->4*/
线程优先级低只是意味着调度的概率低,并不是优先级低就不会被调用了
守护线程
线程分为用户线程(main)和守护线程(gc)虚拟机必须确保用户线程执行完毕虚拟机不用等待守护线程执行完毕
package test;
public class TestThreadDaemon {
public static void main(String[] args) {
God g=new God();
You1 y=new You1();
Thread t1=new Thread(g);
Thread t2=new Thread(y);
t1.setDaemon(true);//默认是false表示用户线程,正常的线程是用户线程
t1.start();
t2.start();
}
}
class God implements Runnable{
@Override
public void run() {
while(true){
System.out.println("god");
}
}
}
class You1 implements Runnable{
@Override
public void run() {
for (int i = 0; i <10 ; i++) {
System.out.println("hello");
}
System.out.println("goodby");
}
}
线程同步sychronized
package test;
import java.util.ArrayList;
public class TestThreadStatic {
public static ArrayList<String> s1=new ArrayList<String>();
public static void main(String[] args) throws InterruptedException {
// ArrayList<String> s1=new ArrayList<String>();
// for (int i = 0; i < 1000; i++) {
// new Thread(()-> {
// synchronized (s1) {
// s1.add(Thread.currentThread().getName());
// }
// }).start();
// }
// Thread.sleep(300);
// System.out.println(s1.size());
add a=new add();
for (int i = 0; i <1000 ; i++) {
new Thread(a,""+i).start();
}
Thread.sleep(300);
s1=a.test();
System.out.println(s1.size());
}
}
class add implements Runnable{
public static ArrayList<String> s1=new ArrayList<String>();
@Override
public void run() {
synchronized (s1) {
s1.add(name());
}
}
public ArrayList<String> test(){
return this.s1;
}
public static String name(){
return Thread.currentThread().getName();
}
}

在这里插入图片描述


Guc
package test;
import java.util.concurrent.CopyOnWriteArrayList;
public class TestThreadGuc {
public static void main(String[] args) {
CopyOnWriteArrayList<String> s=new CopyOnWriteArrayList<String>();
for (int i = 0; i < 1000; i++) {
new Thread(()->s.add(Thread.currentThread().getName())).start();
}
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(s.size());
}
}
死锁
多个线程各自占有一些共享资源,并且互相等待其他线程占有的资源才能运行,而导致两个或者多个线程都在等待对方释放资源,都停止执行的情形,某一个同步块同时拥有“两个以上对象锁”时,就可能会发生死锁
package test;
public class TestThreaddie {
public static void main(String[] args) {
Test r2 = new Test();
Thread t1 = new Thread(r2, "1");
Thread t2 = new Thread(r2, "2");
t1.start();
t2.start();
}
}
class kh {
}
class jz {
}
class Test implements Runnable {
static kh k = new kh();
static jz j = new jz();
@Override
public void run() {
try {
made();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void made() throws InterruptedException {
if (Thread.currentThread().getName().equals("1")) {
synchronized (k) {
System.out.println(Thread.currentThread().getName() + "1这是口红的锁");
Thread.sleep(2000);
synchronized (j) {
System.out.println(Thread.currentThread().getName() + "1这是镜子的锁");
}
}
} else {
synchronized (j) {
System.out.println(Thread.currentThread().getName() + "2这是镜子的锁");
Thread.sleep(4000);
synchronized (k) {
System.out.println(Thread.currentThread().getName() + "2这是口红的锁");
}
}
}
}
}
产生死锁的四个必要条件
互斥条件:一个资源每次只能被一个进程使用。请求与保持条件:一个进程因为请求资源而阻塞时,对已获得的资源保持不放不剥夺条件:进程已获得资源,在未使用完之前,不能强行剥夺。循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
Lock锁
package test;
import java.util.concurrent.locks.ReentrantLock;
public class TestThreadLock {
public static void main(String[] args) {
test2 t=new test2();
Thread r1=new Thread(t);
Thread r2=new Thread(t);
Thread r3=new Thread(t);
r1.start();
r2.start();
r3.start();
}
}
class test2 implements Runnable{
public static int nums=10;
private final ReentrantLock lock=new ReentrantLock();
@Override
public void run() {
while(true){
try {
lock.lock();//加锁
if (nums <= 0) {
break;
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(nums--);
} catch (Exception e) {
e.printStackTrace();
}finally {
lock.unlock();//解锁
}
}
}
}
Lock是显锁(手动开启和关闭锁)synchromized是隐式锁,出作用域自动释放锁Lock只有代码块锁使用Lock锁,JVM将花费较少的时间来调度线程,性能更好。并且具有更好的扩展性(提供更多的子类)
线程协作

在这里插入图片描述


package test;
public class TestThreadgcf {
public static void main(String[] args) {
GZT c = new GZT();
new SC(c).start();
new XF(c).start();
}
}
class SC extends Thread {
GZT g;
public SC(GZT g) {
this.g = g;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
g.push(new CP(i)); System.out.println("生产" + i+" "+g.add());
}
}
}
class XF extends Thread {
GZT g;
public XF(GZT g) {
this.g = g;
}
@Override
public void run() {
for (int i = 0; i <100 ; i++) {
System.out.println("消费了" + g.pop().id+" "+g.add() );
}
}
}
class CP {
int id = 0;
public CP(int id) {
this.id = id;
}
}
class GZT{
CP[] cp = new CP[10];
int sum = 0;
// 生产者生产cp
public synchronized void push(CP cp1) {
if (sum == cp.length) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
cp[sum] = cp1;
sum++;
this.notifyAll();
}
public synchronized CP pop() {
if (sum == 0) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
sum--;
CP cp2 = cp[sum];
this.notifyAll();
return cp2;
}
public int add(){
return sum;
}
}
package test;
/**
* 协作模型:生产者消费者实现方式一:管程法
* 借助缓冲区
* @author
*
// */
//实例:模拟生产馒头
public class TestThreadXHD {
public static void main(String[] args) {
//缓冲区
SynContainer container = new SynContainer();
//生产者
new Productor(container).start();
new Consumer(container).start();
//消费者
}
}
//生产者
class Productor extends Thread{
SynContainer container ;
public Productor(SynContainer container) {
this.container = container;
}
public void run() {
//生产
for(int i=0;i<100;i++) {
System.out.println("生产-->"+i+"个馒头");
container.push(new Steamedbun(i) );
}
}
}
//消费者
class Consumer extends Thread{
SynContainer container ;
public Consumer(SynContainer container) {
this.container = container;
}
public void run() {
//消费
for(int i=0;i<100;i++) {
System.out.println("消费-->"+container.pop().id+"个馒头");
}
}
}
//缓冲区
class SynContainer{
Steamedbun[] buns = new Steamedbun[10]; //存储容器
int count = 0; //计数器
//存储 生产
public synchronized void push(Steamedbun bun) {
//何时能生产 容器存在空间
//不能生产 只有等待
if(count == buns.length) {
try {
this.wait(); //线程阻塞 消费者通知生产解除
} catch (InterruptedException e) {
}
}
//存在空间 可以生产
buns[count] = bun;
count++;
//存在数据了,可以通知消费了
this.notifyAll();
}
//获取 消费
public synchronized Steamedbun pop() {
//何时消费 容器中是否存在数据
//没有数据 只有等待
if(count == 0) {
try {
this.wait(); //线程阻塞 生产者通知消费解除
} catch (InterruptedException e) {
}
}
//存在数据可以消费
count--;
Steamedbun bun = buns[count] ;
this.notifyAll(); //存在空间了,可以唤醒对方生产了
return bun;
}
}
//馒头
class Steamedbun{
int id;
public Steamedbun(int id) {
this.id = id;
}
}

在这里插入图片描述


信号灯法
package test;
public class TestThreadXHD{
public static void main(String[] args) {
TV t=new TV();
pro p1=new pro(t);
watch w1=new watch(t);
p1.start();
w1.start();
}
}
class pro extends Thread{
TV t;
public pro(TV t) {
this.t = t;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
t.play(""+i);
}
}
}
class watch extends Thread{
TV t;
public watch(TV t) {
this.t = t;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
t.watch();
System.out.println(t.vive);
}
}
}
class TV{
String vive;
boolean flast=false;
public synchronized void play(String vi){
if (flast){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("表演了节目"+vi);
flast=!flast;
vive=vi;
this.notifyAll();
}
public synchronized void watch(){
if (!flast){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("观看了"+vive);
this.flast=!flast;
this.notifyAll();
}
}
/*/表演了节目0
//观看了0
//表演了节目1
0
观看了1
1
表演了节目2
观看了2
2
表演了节目3
观看了3
3*/
线程池
思路:提前创建好多个线程,放入线程池中,使用时直接获取,使用完放回池中。可以避免频繁的创建和销毁、实现重复利用好处
提高响应速度(减少创建新线程的时间)降低资源消耗(重复利用线程池中线程,不需要每次都创建)便于线程管理(…)
corePoolSize:核心池的大小mainmumPoolSize:最大线程数keepAliveTime:线程没有任务时最多保持多长时间后会终止
package test;
import org.omg.CORBA.INTERNAL;
import java.util.concurrent.*;
public class TestThreadPool extends Thread{
public static void main(String[] args) {
ExecutorService se= Executors.newFixedThreadPool(10);
se.execute(new MyThread());
se.execute(new MyThread());
se.execute(new MyThread());
se.execute(new MyThread());
se.shutdown();
}
}
class MyThread implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
package test;
import oop.B;
import org.omg.CORBA.INTERNAL;
import java.util.concurrent.*;
public class TestThreadPool extends Thread{
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService se= Executors.newFixedThreadPool(10);
Future<Boolean> t1= se.submit(new MyThread());
Future<Boolean> t2= se.submit(new MyThread());
Future<Boolean> t3= se.submit(new MyThread());
Future<Boolean> t4= se.submit(new MyThread());
System.out.println(t1.get());
System.out.println(t2.get());
System.out.println(t3.get());
System.out.println(t4.get());
se.shutdown();
}
}
class MyThread implements Callable<Boolean>{
@Override
public Boolean call() throws Exception {
System.out.println(Thread.currentThread().getName());
return false;
}
}
和线程池相关的API:ExecutorService和ExecutorsExecutorService:真正的线程池接口,常见子类ThreadPoolExecutorvoid execute(Runnable command):执行任务/命令,没有返回值,一般用来执行Runnable Futuresubmit(Callabletask):执行任务,有返回值,一般用来执行Callablevoid shutdown():关闭线程池Executors:工具类、线程池的工具类,用于创建并返回不同类型的线程池

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_44194174/article/details/112689423

随机推荐

HBase 优化(五)

HBase优化一.高可用二.RowKey设计1.生成随机数、hash、散列值2.字符串反转3.字符串拼接三.内存优化四.基础优化1.允许在HDFS的文件中追加内容2.优化DataNode允许的最大文件...

May--J--Oldhu 阅读(777)

从源码级别深挖Zookeeper监听机制

从源码级别深挖Zookeeper监听机制监听机制是Zookeeper的一个重要特性,例如:Zookeeper实现的高可用集群、分布式锁,就利用到了这一特性。在...

eddieVim 阅读(986)