JavaSE-多线程
JavaSE-多线程
程序、进程、线程
- 程序(program)指的是指令和数据的有序集合,其本身没有运行的含义,是一个静态的概念。
- 进程(process)指的是一个程序执行一次的过程,他是一个动态的概念,是系统分配资源的单位
- 线程(thread),通常在一个进程中可以有多个线程,但是在进程中至少存在一个线程(主线程),是CPU调度和执行的单位
真正的多线程指的是有多个CPU,即多核。
在程序运行时,即便没有自己创建线程也会有很多线程,如主线程、gc线程、
在一个进程中,如果开辟了多个线程,线程的运行由调度器(CPU)安排调度,调度器是与操作系统密切相关的,先后顺序不能人为干预
对一份资源进行操作时,会存在资源抢夺问题,需要加入并发控制,对线程排队
每个线程在自己的工作内存交互,内存控制不当会导致数据不一致
线程实现
- 继承
Thread
类 - 实现
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
- 自定义线程继承
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; //网络文件的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
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 {
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);
}
}
}
所有内容仅限于维护网络安全学习参考