Loading

JavaSE-多线程

JavaSE-多线程

程序、进程、线程

  • 程序(program)指的是指令和数据的有序集合,其本身没有运行的含义,是一个静态的概念。
  • 进程(process)指的是一个程序执行一次的过程,他是一个动态的概念,是系统分配资源的单位
  • 线程(thread),通常在一个进程中可以有多个线程,但是在进程中至少存在一个线程(主线程),是CPU调度和执行的单位

真正的多线程指的是有多个CPU,即多核。

在程序运行时,即便没有自己创建线程也会有很多线程,如主线程、gc线程、

在一个进程中,如果开辟了多个线程,线程的运行由调度器(CPU)安排调度,调度器是与操作系统密切相关的,先后顺序不能人为干预

对一份资源进行操作时,会存在资源抢夺问题,需要加入并发控制,对线程排队

每个线程在自己的工作内存交互,内存控制不当会导致数据不一致

线程实现

  1. 继承Thread
  2. 实现 Runable 接口

ps:因为Java是单继承,建议使用Runable接口实现多线程。方便同一个对象被多个线程使用

TestThread testThread = new TestThread();

new Thread(testThread,"线程1").start()
new Thread(testThread,"线程2").start()
new Thread(testThread,"线程3").start()

extends Thread

  1. 自定义线程继承Thread
  2. 重写run()方法,编写线程执行体
  3. 创建线程对象,调用start()方法启动现场,但线程不一定立即执行,听CPU安排调度
//创建线程1:继承Thread类,重写run()方法,调用start()方法执行线程
public class CreateThreadDemo01 extends Thread{

    //重写run()方法

    @Override
    public void run() {
        //run线程,run()方法体
        System.out.println("Run()线程========" + i);
    }

    public static void main(String[] args) {

        //main线程,主线程
        //创建一个线程对象
        CreateThreadDemo01 createThreadDemo01 = new CreateThreadDemo01();

        //调用start()方法执行线程
        createThreadDemo01.start();

        for (int i = 0; i < 2000; i++) {
            System.out.println("Main线程========" + i);
        }

    }
}

其中,主线程和run()方法线程交替执行,并不存在先后顺序。

线程开启不一定立即执行,由CPU调度执行。

加载第三方工具类库

新建一个lib包,将下载好的jar包cv到lib包中,并右键 Add as Library

在项目资源目录Project StructureLibraries下就可以看到这个jar包了

继承Thread类下载文件

  1. 继承Thread方法
  2. 创建一个类,在其中创建一个方法调用org.apache.commons.io.中的FileUtils.copyURLToFile()方法下载网络上的文件
  3. 重写run()方法调用上面写好的下载文件的方法
  4. 创建有参构造方法使新建thread时可以直接穿入参数urlfilename
  5. main()方法中新建子线程并start()子线程
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;

//练习Thread 实现多线程同步下载
public class TestThreadDemo02 extends Thread{

    private String url;	//网络文件的url
    private String filename;	//要保存的文件名

    @Override
    public void run() {
        //子线程要进行的操作
        WebDownloader webDownloader = new WebDownloader();
        webDownloader.downloader(url, filename);
        System.out.println("文件下载完成,位于: " + filename);

    }
  
		//有参构造方法
    public TestThreadDemo02(String url, String filename){
        this.url = url;         
        this.filename = filename;       
    }

    public static void main(String[] args) {

      	//创建子线程
        TestThreadDemo02 thread01 = new TestThreadDemo02("https://pic.cnblogs.com/avatar/1835657/20210311181843.png",
                "/Users/b/Desktop/01.png");
        TestThreadDemo02 thread02 = new TestThreadDemo02("https://pic.cnblogs.com/avatar/1835657/20210311181843.png",
                "/Users/b/Desktop/02.png");
        TestThreadDemo02 thread03 = new TestThreadDemo02("https://images.cnblogs.com/cnblogs_com/ache/1644357/o_20022410503214.jpg",
                "/Users/b/Desktop/03.jpg");
				//运行子线程
        thread01.start();   
        thread02.start();
        thread03.start();

    }
}

class WebDownloader {
    public void downloader(String url, String filename){
        try {
            FileUtils.copyURLToFile(new URL(url), new File(filename));
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("IO错误,WebDownloader方法存在问题");
        }
    }
}

implements Runable

  1. implements Runnable接口
  2. 重写run()方法
  3. 需要一个实现Runable接口的类的对象作为参数传入Thread类中调用start()方法
//实现runable接口,重写run方法,需要一个runable接口的实现类作为参数传入thread类中调用start方法 实现多线程
//实现runable接口
public class RunableThreadDemo01 implements Runnable{


    public static void main(String[] args) {
        //new一个runable接口的实现类
        RunableThreadDemo01 runableThreadDemo01 = new RunableThreadDemo01();

        //传入实现类并调用start
        new Thread(runableThreadDemo01).start();

        for (int i = 0; i <2000; i++) {
            System.out.println("main线程========" + i);
        }

    }

    //重写run方法
    @Override
    public void run() {
        for (int i = 0; i < 200; i++) {
            System.out.println("run线程===========" + i);
        }
    }
}

实现Runable接口多线程下载文件

import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;

//实现多线程
public class TestThreadDemo01 implements Runnable{

    private String url;
    private String filename;

    @Override
    public void run() {
        //子线程要进行的操作
        WebDownloader02 webDownloader02 = new WebDownloader02();
        webDownloader02.downloader(url, filename);
        System.out.println("文件下载完成,位于: " + filename);

    }

    public TestThreadDemo01(String url, String filename){
        this.url = url;         //网络文件的url
        this.filename = filename;       //文件名
    }

    public static void main(String[] args) {

        TestThreadDemo02 thread01 = new TestThreadDemo02("https://pic.cnblogs.com/avatar/1835657/20210311181843.png",
                "/Users/b/Desktop/01.png");
        TestThreadDemo02 thread02 = new TestThreadDemo02("https://pic.cnblogs.com/avatar/1835657/20210311181843.png",
                "/Users/b/Desktop/02.png");
        TestThreadDemo02 thread03 = new TestThreadDemo02("https://images.cnblogs.com/cnblogs_com/ache/1644357/o_20022410503214.jpg",
                "/Users/b/Desktop/03.jpg");

        new Thread(thread01).start();   //运行该子线程
        new Thread(thread02).start();
        new Thread(thread03).start();

    }
}

class WebDownloader02 {
    public void downloader(String url, String filename){
        try {
            FileUtils.copyURLToFile(new URL(url), new File(filename));
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("IO错误,WebDownloader方法存在问题");
        }
    }
}

多个线程操作一个对象

public class TestThreadDemo03 implements Runnable{

    private int ticketNums = 10;

    @Override
    public void run() {
        while (true){
            if (ticketNums >= 0){
                try {
                    //模拟延时
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "拿到了第" + ticketNums + "票");
                ticketNums--;
            }else{
                break;
            }
        }
    }


    public static void main(String[] args) {

        TestThreadDemo03 testThreadDemo03 = new TestThreadDemo03();

        new Thread(testThreadDemo03, "Ago").start();
        new Thread(testThreadDemo03, "Kfei").start();
        new Thread(testThreadDemo03, "Xming").start();
        new Thread(testThreadDemo03, "Zgou").start();

    }
}

运行结果,其中Kfei和Ago都拿到了第2票,第10票,多个线程操作同一个资源时出现数据混乱的问题

Kfei拿到了第10票
Ago拿到了第10票
Kfei拿到了第9票
Ago拿到了第8票
Kfei拿到了第7票
Ago拿到了第6票
Kfei拿到了第5票
Ago拿到了第4票
Ago拿到了第2票
Kfei拿到了第2票
Ago拿到了第1票
Kfei拿到了第0票

线程状态

线程五大状态

  1. 创建状态:当new一个新的线程对象时,就进入了创建状态
  2. 就绪状态:当调用start()方法时,线程进入就绪状态,但不是立即执行,需要等待CPU调度
  3. 阻塞状态:当调用sleep()wait()或同步锁定时,线程进入阻塞状态,等阻塞事件结束后重新进入就绪状态
  4. 运行状态:获得CPU资源真正开始运行线程
  5. 死亡状态:线程中断或结束

线程方法

方法 说明
setPriority(int newPriority) 更改线程优先级
static void sleep(long millis) 使当前线程休眠指定的毫秒数
void join() 等待该线程中止
static void yeild() 暂停当前执行的线程对象,并执行其他线程
void interupt() 中断线程(不建议)
boolean isAlive() 判断线程是否存活

停止线程

推荐设置循环次数使用标志位来控制线程的启停

//建立标志位,
    private boolean flag = true;

    @Override
    public void run() {
        //利用标志位控制线程启停
        int i = 0;
        while (flag){
            System.out.println("线程" + Thread.currentThread().getName() + "开始 " + i++);
        }
    }

    //对外提供方法用于停止线程
    public void stop(){
        this.flag = false;
        System.out.println("线程" + Thread.currentThread().getName() + "结束");
    }
		public static void main(String[] args) {
        	TestStopDemo testStopDemo = new TestStopDemo();
       	  new Thread(testStopDemo, "Thread1").start();
       	  new Thread(testStopDemo, "Thread2").start();
        
         testStopDemo.stop();     

        }

线程休眠 sleep()

 @Override
    public void run() {
        while (true){
            if (ticketNums >= 0){
                try {
                    //模拟延时
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                
            }
        }
    }

模拟倒计时

public class TestTimeDownDemo implements Runnable{
    @Override
    public void run() {
        Date starttime = new Date(System.currentTimeMillis());//获取系统当前时间

        while (true){
            try {
                Thread.sleep(1000);
                System.out.println(new SimpleDateFormat("HH:mm:ss").format(starttime));
                starttime = new Date(System.currentTimeMillis());//更新当前时间
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }


    public static void main(String[] args) {
        TestTimeDownDemo testTimeDownDemo = new TestTimeDownDemo();
        new Thread(testTimeDownDemo).start();
    }
}

线程礼让 yield()

礼让不一定成功,看CPU

public class TestYieldDemo {

    public static void main(String[] args) {
        MyYield myYield = new MyYield();
        new Thread(myYield,"thread1").start();
        new Thread(myYield,"thread2").start();
    }

}

class MyYield implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + "线程开始执行");
        Thread.yield();     //线程礼让
        System.out.println(Thread.currentThread().getName() + "线程停止执行");
    }
}

线程强制执行 join()

Join()合并线程,待此线程运行结束后,再执行其他线程,这期间其他线程阻塞

public class TestJoinDemo implements Runnable{

    @Override
    public void run() {
        for (int i = 0; i < 20000; i++) {
            System.out.println("join线程执行" + i);
        }
    }

    public static void main(String[] args) {
        //执行子线程
        TestJoinDemo testJoinDemo = new TestJoinDemo();

        Thread thread = new Thread(testJoinDemo);
        thread.start();

        //main线程
        for (int i = 0; i < 200; i++) {
            if (i==20){
                try {
                    thread.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("main线程" + i);

        }
    }
}
posted @ 2021-07-19 14:08  Zh1z3ven  阅读(91)  评论(0编辑  收藏  举报