您的位置:首页 > 编程语言 > Java开发

JavaSE-多线程

2021-07-19 14:08 711 查看

JavaSE-多线程

程序、进程、线程

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

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

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

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

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

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

线程实现

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

ps:因为Java是单继承,建议使用

Runable
接口实现多线程。方便同一个对象被多个线程使用

T
ad8
estThread 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 Structure
Libraries
下就可以看到这个jar包了

继承Thread类下载文件

  1. 继承
    Thread
    方法
  2. 创建一个类,在其中创建一个方法调用
    org.apache.commons.io.
    中的
    FileUtils.copyURLToFile()
    方法下载网络上的文件
  3. 重写
    run()
    方法调用上面写好的下载文件的方法
  4. 创建有参构造方法使新建
    thread
    时可以直接穿入参数
    url
    filename
  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;	//网
56c
络文件的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) {

1043
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. 死亡状态:线程中断或结束

线程方法

ad8
方法 说明
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 {

1044
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);

}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: