JavaSE-多线程
2021-07-19 14:08
711 查看
JavaSE-多线程
程序、进程、线程
- 程序(program)指的是指令和数据的有序集合,其本身没有运行的含义,是一个静态的概念。
- 进程(process)指的是一个程序执行一次的过程,他是一个动态的概念,是系统分配资源的单位
- 线程(thread),通常在一个进程中可以有多个线程,但是在进程中至少存在一个线程(主线程),是CPU调度和执行的单位
真正的多线程指的是有多个CPU,即多核。
在程序运行时,即便没有自己创建线程也会有很多线程,如主线程、gc线程、
在一个进程中,如果开辟了多个线程,线程的运行由调度器(CPU)安排调度,调度器是与操作系统密切相关的,先后顺序不能人为干预
对一份资源进行操作时,会存在资源抢夺问题,需要加入并发控制,对线程排队
每个线程在自己的工作内存交互,内存控制不当会导致数据不一致
线程实现
- 继承
Thread
类 - 实现
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
- 自定义线程继承
Thread
类 - 重写
run()
方法,编写线程执行体 - 创建线程对象,调用
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类下载文件
- 继承
Thread
方法 - 创建一个类,在其中创建一个方法调用
org.apache.commons.io.
中的FileUtils.copyURLToFile()
方法下载网络上的文件 - 重写
run()
方法调用上面写好的下载文件的方法 - 创建有参构造方法使新建
thread
时可以直接穿入参数url
和filename
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
implements Runnable
接口- 重写
run()
方法 - 需要一个实现
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票线程状态
线程五大状态
- 创建状态:当
new一个新的线程对象时,就进入了创建状态- 就绪状态:当调用
start()方法时,线程进入就绪状态,但不是立即执行,需要等待CPU调度- 阻塞状态:当调用
sleep()、wait()或同步锁定时,线程进入阻塞状态,等阻塞事件结束后重新进入就绪状态- 运行状态:获得CPU资源真正开始运行线程
- 死亡状态:线程中断或结束
线程方法
方法 | 说明 |
---|---|
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); } } }
相关文章推荐
- javase的多线程断点下载
- javaSE-多线程
- 学习笔记之JavaSE(23)--多线程3
- JavaSE——多线程:线程的同步与死锁
- JavaSE复习之十二 高级特性:并发 (多线程) 补充(2)
- 黑马程序员——javaSE_多线程
- 黑马程序员—javaSE—多线程(三)
- JavaSE 多线程
- [置顶] javaSE-(多线程)
- JavaSE——多线程:ThreadLocal详解
- javaSE知识点,String类、多线程
- javase复习整理(一):基础要点、重点、易错点、多线程梳理总结
- Javase—Thread多线程
- JavaSE学习总结第24天_多线程2
- javase--多线程总结。
- JavaSE(19)(两种开启多线程方式)
- JavaSE 多线程 线程间通信示例-1
- 【JavaSE笔记】多线程(二)多线程
- JavaSe(多线程)
- javaSE-多线程间通信-生产者消费者例子