首页 > 其他分享 >多线程

多线程

时间:2023-04-01 17:44:45浏览次数:31  
标签:Thread void 线程 println new 多线程 public

内容

  • 什么是线程
  • 如何创建线程
  • 线程的调度
  • 线程的一个设计模式:生产消费者模型
  • 线程池
  • 线程集合对象(侧重点)

一、什么是线程

进程:运行中的程序才可以称为进程,一个程序一个进程。宏观并行,微观串行。

线程:

1.任何一个程序都至少拥有一个线程,即主线程。但是java程序默认有两个线程,除了主线程之外,还有一个线程,即用于垃圾回收的守护线程。

2.线程是一种轻量级进程,在CPU当中的最基本单元是线程。

3.一个进程可以包含若干的线程

4.各进程之间不共享内存,同进程的各线程之间共享内存

5.每个线程都有独立的栈空间

6.堆当中的地址,可以被共享

注意:

线程是不可控的,只能调度,无法精确控制。研究线程,研究的是如何在多线程场景中,保证数据读写的安全,以及调度线程的运行状态

二、线程的创建和使用

1.通过Thread类来进行创建,需要继承Thread类

package com.mine.demo01;
public class Main1 {
    public static void main(String[] args) {
        MyThread1 mt1 = new MyThread1();
        mt1.start();//调用的不是run方法,而是start
    }
}
class MyThread1 extends Thread{
    @Override
    public void run() {
        System.out.println("线程运行了");
    }
}

2.通过实现Runnable接口来创建

package com.mine.demo01;
public class Main2 {
    public static void main(String[] args) {
        Thread t = new Thread(new MyThread2());
        t.start();
    }
}
class MyThread2 implements Runnable{
    @Override
    public void run() {
        System.out.println("线程被运行了");
    }
}

每个线程的逻辑,都是在run方法当中运行的。通过调用start方法来执行线程。start方法只能被调用一次。

3.线程名的创建和获取

Thread t = new Thread(new MyThread2(),"mythreadName2");
t.setName("myNewThreadName2");
t.start();

线程的线程名,需要在启动之前就确定好。

每个线程都有一个默认的名字:Thread-N,N是线程建立的顺序,是一个不重复的正整数

4.获取线程名的方式

在每一个线程的线程栈当中,调用Thread.currentThread().getName()获取线程名

package com.mine.demo01;
public class Main3 {
    public static void main(String[] args) {
        System.out.println("主线程:"+Thread.currentThread().getName());
        Thread t = new Thread(new MyThread3());
        t.start();
    }
}
class MyThread3 implements Runnable {
    @Override
    public void run() {
        System.out.println("子线程:" + Thread.currentThread().getName());
    }
}

结果:
主线程:main
子线程:Thread-0

三、线程调度

线程之间传参,共享数据

synchronized:同一时刻,只有一个线程可以调用该方法。

package com.mine.demo01;
public class Main4 {
    public static void main(String[] args) {
        Test t = new Test();
        for (int i = 0 ; i < 1000 ; i ++){
            new Thread(new Thread1(t)).start();
        }
    }
}
//线程数据的共享和传参
class Test{
    private int i = 0;
    //为了保证数据安全,需要用到同步锁
    public synchronized int getI() {
        return ++i;
    }
}
class Thread1 implements Runnable{
    private Test t;
    public Thread1(Test t){
        this.t = t;
    }
    @Override
    public void run() {
        System.out.println(t.getI());
    }
}
  • 一个正常线程的生命周期

1.新建线程(1生命形态)
2.启动线程
3.就绪状态(2就绪形态)

4.等待系统分配资源
5.运行状态(3运行形态)
6.死亡状态(4死亡形态)

1.等待

等待的构成:
1.新建
2.就绪
3.运行
4.持锁(先到就绪状态---->运行)
5.等待
6.释放锁
7.时间到或者被唤醒
8.持锁(先到就绪状态---->运行)
9.执行等待后续
10.死亡

注意:等待必须在同步环境当中,如果不在同步环境中,会报如下异常

java.lang.RuntimeException: java.lang.IllegalMonitorStateException
	at com.qf.demo01.Test.getI(Main4.java:18)
	at com.qf.demo01.Thread1.run(Main4.java:30)
	at java.lang.Thread.run(Thread.java:745)
package com.mine.demo01;

public class Main4 {
    public static void main(String[] args) {
        Test t = new Test();
        for (int i = 0; i < 3; i++) {
            new Thread(new Thread1(t)).start();
        }
    }
}

class Test {
    private int i = 0;

    public synchronized int getI() {
        try {
            System.out.println("等待开始前:" + Thread.currentThread().getName());
            this.wait(3000);
            System.out.println("等待开始后:" + Thread.currentThread().getName());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return ++i;
    }
}

class Thread1 implements Runnable {
    private Test t;

    public Thread1(Test t) {
        this.t = t;
    }

    @Override
    public void run() {
        System.out.println(t.getI());
    }
}

运行结果:

等待开始前:Thread-0
等待开始前:Thread-2
等待开始前:Thread-1
等待开始后:Thread-2
1
等待开始后:Thread-1
2
等待开始后:Thread-0
3

注意:只要是线程进入阻塞,那么他一定回先回到就绪状态

2.休眠

package com.mine.demo05;

public class Main {
    private synchronized static void test(){
        try {
            System.out.println("休眠前:"+Thread.currentThread().getName());
            Thread.sleep(3000);
            System.out.println("休眠后:"+Thread.currentThread().getName());
        }catch (InterruptedException e){
            throw new RuntimeException(e);
        }
    }
    public static void main(String[] args) {
        for (int i = 0;i < 2 ;i++){
            Thread t = new Thread(new Runnable() {
                @Override
                public void run() {
                    test();
                }
            });
            t.start();
        }
    }
}

结果:
休眠前:Thread-0
休眠后:Thread-0
休眠前:Thread-1
休眠后:Thread-1

注意:休眠不释放锁,休眠不可被唤醒,必须等到休眠时间结束

3.优先级(了解)

Thread t = new MyThread();
t.setPriority(5);
t.start();

4.让步(了解)

Thread.yield();//作用仅仅是让当前正在运行的线程回到就绪状态

5.线程的join(生命周期和sleep是一样的)

package com.mine.demo06;

public class Main {
    public static void main(String[] args) {
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"......");
                try {
                    Thread.sleep(3000);//3s
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"++++++");
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });

        try {
            t1.start();
            t1.join();
            t2.start();
            t2.join();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

    }
}


结果:
Thread-0......
Thread-1++++++

6.守护线程

用户线程:主帅,用户线程只要在运行,守护线程可以一直运行下去,除非守护线程自行死亡

守护线程:卫兵,只要没有用户线程还在继续执行,那么无论其是否还存活,都将立即死亡

四、同步锁

注意:只要是改数据就,就一定要考虑数据同步问题

  • 对象锁
  //同步方法
    public synchronized void getI() {
        System.out.println(Thread.currentThread().getName()+"持锁");
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
public void test(){
        System.out.println(Thread.currentThread().getName()+" "+i);
        synchronized (this){//同步代码块
            System.out.println(Thread.currentThread().getName()+"持锁");
            try {
                Thread.sleep(3000);
                i++;
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
        System.out.println(i);
    }

基于对象的锁,必须是多线程共享的同一个对象

 //基于对象的锁
        private A a = new A();
        public void test(){
            // A a = new A();
            System.out.println(Thread.currentThread().getName()+" "+i);
            synchronized(a){
                System.out.println(Thread.currentThread().getName()+"持锁");
                try {
                    Thread.sleep(3000);
                    i++;
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
            System.out.println(i);
        }
  • 类锁
package com.mine.demo02;
public class Main2 {
    public static void main(String[] args) {
        for(int i = 0 ; i < 3 ; i ++){
            new Thread(new Runnable() {
                @Override
                public void run() {
                    C.fun1();
                }
            }).start();
        }
    }
}
class C{
    public synchronized static void fun1(){
        try {
            System.out.println(Thread.currentThread().getName());
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}
public static void fun2(){
	synchronized(C.class){
		try {
			System.out.println(Thread.currentThread().getName());
			Thread.sleep(3000);
		} catch (InterruptedException e) {
				throw new RuntimeException(e);
		}
    }
}
  • 死锁
package com.mine.demo02;
public class Main1 {
    public static void main(String[] args) {
        Test t = new Test();
        new Thread(new Thread1(t)).start();
        new Thread(new Thread2(t)).start();
    }
}
class Test{
    private A a = new A();
    private B b = new B();
    public void test1(){
        synchronized(b){
            System.out.println(Thread.currentThread().getName()+"持b锁");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            synchronized(a){
                System.out.println(Thread.currentThread().getName()+"持a锁");
            }
        }
    }
    public void test2(){
        synchronized(a){
            System.out.println(Thread.currentThread().getName()+"持a锁");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            synchronized(b){
                System.out.println(Thread.currentThread().getName()+"持b锁");
            }
        }
    }
}
class Thread1 implements Runnable{
    private Test t;
    public Thread1(Test t){
        this.t = t;
    }
    @Override
    public void run() {
        t.test1();
    }
}
class Thread2 implements Runnable{
    private Test t;
    public Thread2(Test t){
        this.t = t;
    }
    @Override
    public void run() {
        t.test2();
    }
}
class A{}
class B{}

注意:
1.静态锁只和静态锁一起用,对象锁只和对象锁一起用,不要混用。
2.持锁顺序保持一致

五、volatile关键字

是一个轻量级的同步锁,因为互斥是同步中最消耗性能的地方,而在读-读/读-写(多读1写),那么这
种情况就只需要考虑可见性。
同步锁的功能包括:互斥,可见

package com.mine.demo02;
public class Person {
    private volatile Integer id;
    private volatile String name;
    public Integer getId() {
        return id;
    }
    public synchronized void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public synchronized void setName(String name) {
        this.name = name;
    }
}

六、生产消费者模型

package com.mine.demo03;
import java.util.Date;
//生成者
public class Producer implements Runnable {
    private final Queue queue;
    public Producer(final Queue queue) {
        this.queue = queue;
    }
    @Override
    public void run() {
        for(;;){
            try {
                Thread.sleep(1000);
                this.queue.add(Thread.currentThread().getName() + " " + new
                        Date().getTime());
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}
}
package com.mine.demo03;
import java.util.Date;
//消费者
public class Consumer implements Runnable{
    private final Queue queue;
    public Consumer(final Queue queue) {
        this.queue = queue;
    }
    @Override
    public void run() {
        for(;;){
            try {
                Thread.sleep(1000);
                System.out.println(this.queue.get());
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}


package com.qf.demo03;
import java.util.LinkedList;
//队列
public class Queue{
    private static final int MAX_VALUE = 5;
    private LinkedList queue = new LinkedList();
    public synchronized void add(Object obj){
        while(queue.size()==MAX_VALUE){//用while不要用if
            try {
                //满了等待
                System.out.println(Thread.currentThread().getName() + " 满了,等
                        待!!");
                this.wait();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
        //没有满,添加
        this.queue.addFirst(obj);
        //每次添加唤醒全部线程
        this.notifyAll();
    }
    public synchronized Object get(){
        while (this.queue.size() == 0){
            //空了等待
            try {
                System.out.println(Thread.currentThread().getName() + " 空了,等
                        待!!");
                this.wait();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
        //不为空
        Object obj = this.queue.getLast();
        this.queue.removeLast();
        //每次获取唤醒全部线程
        this.notifyAll();
        return obj;
    }
}
package com.mine.demo03;

import com.oracle.jrockit.jfr.Producer;

import java.util.function.Consumer;

public class Main {
    public static void main(String[] args) {
        Queue queue = new Queue();
        new Thread(new Producer(queue)).start();
        new Thread(new Producer(queue)).start();
        new Thread(new Consumer(queue)).start();
    }
}

标签:Thread,void,线程,println,new,多线程,public
From: https://www.cnblogs.com/DFshmily/p/17278991.html

相关文章

  • Java多线程(一篇从0讲透)
    多线程思维导图看天下:1.概述并行与并发并行:指两个或多个事件在同一时刻发生(同时发生)并发:指两个或多个事件在同一个时间段内发生。(交替执行)线程与进程进程:是指一个内存中运行的程序,每个进程都有一个独立的内存空间,一个应用程序可以同时运行多个进程记忆:进程的英文......
  • 多线程相关的问题(面试)
    1、线程创建的方式有哪几种1、继承Thread类;2、实现Runnable接口;3、实现Callable接口;4、使用Executor工具类创建线程池;5;使用ThreadPoolExecutor工具类创建线程池。2、线程的5种状态流转线程的状态如下状态:新建、就绪、运行、【阻塞】(等待(时间片用尽)、主动等待、挂起)、......
  • 结合 操作系统、Java多线程 学习并发编程
    为什么我们需要考虑并发?不考虑的话会出现什么问题?并发的多个程序(进程/线程)会对计算机资源进行争夺,如果不加以控制会出现混乱、严重影响程序运行效率,甚至错误首先是对CPU时间片的争夺对于多线程编程而言,由于创建线程后,线程的执行顺序是由调度程序控制的,也就是说各个线程的执行顺......
  • 多线程简介以及线程同步
    1.实现多线程1.1简单了解多线程【理解】是指从软件或者硬件上实现多个线程并发执行的技术。具有多线程能力的计算机因有硬件支持而能够在同一时间执行多个线程,提升性能。1.2并发和并行【理解】并行:在同一时刻,有多个指令在多个CPU上同时执行。并发:在同一时刻,有多个指令......
  • c++ 多线程编程std::thread, std::shared_mutex, std::unique_lock
    在C++11新标准中,可以简单通过使用thread库,来管理多线程,使用时需要#include<thread>头文件。简单用例如下:1std::thread(Simple_func);2std::threadt(Simple_func);3t.detach();第一行是直接启动一个新线程来执行Simple_func函数,而第二行先声明一个线程函数t(返回类型为......
  • 多线程队列接收
    packageorg.example.file.mult;//函数值接口@FunctionalInterfacepublicinterfaceFuncationCallback{voidcallback(Stringparam);} 回调接收 packageorg.example.file.mult;importjava.util.ArrayList;publicclassFuncationCallbackImpl{......
  • C#:多线程
    在C#中,多线程是一种非常常见的编程方式,它可以提高程序的并发性和响应性。但是,多线程编程也是一种比较复杂的编程方式,需要开发者具备一定的经验和技能。本文将介绍C#中多......
  • 多线程源码_三菱plc+卡+串口上位机
    多线程源码_三菱plc+卡+串口上位机1,采用C#编程。2,上位机采用RS232串口通信链接plc。3,PLC为三菱。4,研华采集卡,采集压装电压。5,曲线判据自定义。6,每天作业......
  • 【Redis】多线程Redis的N种架构
    【Redis】多线程Redis的N种架构为什么需要多线程的Redis在单点上利用更多的资源--热点资源官方的多线程只看左边部分其实还是单线程的形式,设置io Thread的数量==》......
  • 多线程 互斥锁与读写锁 概念
    一、多线程lock互斥锁简述多线程环境中,不使用lock锁,会形成竞争条件,导致A线程与B线程数据使用冲突。使用lock锁可以保证当有线程操作某个共享资源时,能使该代码块按照指......