- Process与Thread(进程和线程)
程序是指令和数据的集合,是一个静态的概念。
进程则是执行程序的一次过程,是动态的概念,是系统资源分配的单位。
通常一个进程中可以包含若干个线程,一个进程中至少有一个线程,不然没有存在的意义,线程是CPU调度和执行的单位。
例如:一个视频是一个进程,那么其中有播放声音、显示画面、看弹幕等多个线程。(main()相当于主线程,其他的方法为其他的线程)
- 创建线程
方式一:继承Thread类,重写run() ,调用start()开启线程
调用run()方法按顺序依次执行
package 多线程;
//继承Thread类,重写run,调用start开启线程
public class Create extends Thread{
@Override
public void run() {
//run方法线程体
for(int i = 0;i<20;++i){
System.out.println("我在看代码--" + i);
}
}
public static void main(String[] args) {
//主方法main线程,主线程
//创建一个线程对象
Create create = new Create();
//调用run方法按顺序执行
create.run();
for (int i = 0; i < 20; i++) {
System.out.println("我在学习多线程--" + i);
}
}
}
/*
结果为:
D:\Java\jdk\bin\java.exe "-javaagent:D:\java\IntelliJ IDEA Educational Edition 2020.1.1\lib\idea_rt.jar=64891:D:\java\IntelliJ IDEA Educational Edition 2020.1.1\bin" -Dfile.encoding=UTF-8 -classpath D:\java\jdk\jre\lib\charsets.jar;D:\java\jdk\jre\lib\deploy.jar;D:\java\jdk\jre\lib\ext\access-bridge-64.jar;D:\java\jdk\jre\lib\ext\cldrdata.jar;D:\java\jdk\jre\lib\ext\dnsns.jar;D:\java\jdk\jre\lib\ext\jaccess.jar;D:\java\jdk\jre\lib\ext\jfxrt.jar;D:\java\jdk\jre\lib\ext\localedata.jar;D:\java\jdk\jre\lib\ext\nashorn.jar;D:\java\jdk\jre\lib\ext\sunec.jar;D:\java\jdk\jre\lib\ext\sunjce_provider.jar;D:\java\jdk\jre\lib\ext\sunmscapi.jar;D:\java\jdk\jre\lib\ext\sunpkcs11.jar;D:\java\jdk\jre\lib\ext\zipfs.jar;D:\java\jdk\jre\lib\javaws.jar;D:\java\jdk\jre\lib\jce.jar;D:\java\jdk\jre\lib\jfr.jar;D:\java\jdk\jre\lib\jfxswt.jar;D:\java\jdk\jre\lib\jsse.jar;D:\java\jdk\jre\lib\management-agent.jar;D:\java\jdk\jre\lib\plugin.jar;D:\java\jdk\jre\lib\resources.jar;D:\java\jdk\jre\lib\rt.jar;D:\JavaSE\基础语法\out\production\基础语法 多线程.Create
我在看代码--0
我在看代码--1
我在看代码--2
我在看代码--3
我在看代码--4
我在看代码--5
我在看代码--6
我在看代码--7
我在看代码--8
我在看代码--9
我在看代码--10
我在看代码--11
我在看代码--12
我在看代码--13
我在看代码--14
我在看代码--15
我在看代码--16
我在看代码--17
我在看代码--18
我在看代码--19
我在学习多线程--0
我在学习多线程--1
我在学习多线程--2
我在学习多线程--3
我在学习多线程--4
我在学习多线程--5
我在学习多线程--6
我在学习多线程--7
我在学习多线程--8
我在学习多线程--9
我在学习多线程--10
我在学习多线程--11
我在学习多线程--12
我在学习多线程--13
我在学习多线程--14
我在学习多线程--15
我在学习多线程--16
我在学习多线程--17
我在学习多线程--18
我在学习多线程--19
进程已结束,退出代码0
*/
调用start()方法穿插执行代码,并且每次运行的结果都不相同(穿插顺序不同)
package 多线程;
//继承Thread类,重写run,调用start开启线程
public class Create extends Thread{
@Override
public void run() {
//run方法线程体
for(int i = 0;i<20;++i){
System.out.println("我在看代码--" + i);
}
}
public static void main(String[] args) {
//主方法main线程,主线程
//创建一个线程对象
Create create = new Create();
//调用start()方法,开启线程
create.start();
for (int i = 0; i < 20; i++) {
System.out.println("我在学习多线程--" + i);
}
}
}
/*
结果为:
我在学习多线程--0
我在看代码--0
我在学习多线程--1
我在看代码--1
我在看代码--2
我在看代码--3
我在看代码--4
我在看代码--5
我在学习多线程--2
我在看代码--6
我在看代码--7
我在看代码--8
我在学习多线程--3
我在学习多线程--4
我在看代码--9
我在学习多线程--5
我在看代码--10
我在看代码--11
我在学习多线程--6
我在看代码--12
我在学习多线程--7
我在看代码--13
我在学习多线程--8
我在看代码--14
我在学习多线程--9
我在看代码--15
我在学习多线程--10
我在看代码--16
我在学习多线程--11
我在看代码--17
我在学习多线程--12
我在看代码--18
我在学习多线程--13
我在看代码--19
我在学习多线程--14
我在学习多线程--15
我在学习多线程--16
我在学习多线程--17
我在学习多线程--18
我在学习多线程--19
进程已结束,退出代码0
*/
下面为一个多线程图片保存的实例:
package 多线程;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
//练习Thread,实现多线程同步下载图片
public class PicLoad extends Thread{
private String url;
private String name;
public PicLoad(String url, String name) {
this.url = url;
this.name = name;
}
@Override
public void run() {
WebDownloader webDownloader = new WebDownloader();
webDownloader.downloader(url, name);
System.out.println("下载了文件名为:" + name);
}
}
//下载器
class WebDownloader{
//下载方法
public void downloader(String url, String name){
try {
FileUtils.copyURLToFile(new URL(url), new File(name));
} catch (IOException e) {
System.out.println("IO异常,downloader方法出现问题");
}
}
}
class Test{
public static void main(String[] args) {
PicLoad p1 = new PicLoad("https://pic1.zhimg.com/80/v2-86c0da0f749a46a1a7a2c7b80465d530_720w.jpg?source=1940ef5c", "qzy.jpg");
PicLoad p2 = new PicLoad("https://ts1.cn.mm.bing.net/th?id=OIP-C.5eGvoxrfiCR8-F954A0g2gAAAA&w=146&h=170&c=8&rs=1&qlt=90&o=6&dpr=1.25&pid=3.1&rm=2", "bqb.jpg");
PicLoad p3 = new PicLoad("https://ts1.cn.mm.bing.net/th?id=OIP-C.q5iRYT4Q_g_r7UBqAON9UwAAAA&w=146&h=170&c=8&rs=1&qlt=90&o=6&dpr=1.25&pid=3.1&rm=2", "xzc.jpg");
p1.start();
p2.start();
p3.start();
}
}
/*
结果为:
下载了文件名为:qzy.jpg
下载了文件名为:xzc.jpg
下载了文件名为:bqb.jpg
*/
结果成功保存了三张图片,但是保存顺序发生了变化,即为多线程的理念。
方法二:实现Runnable接口(推荐)
定义MyRunna类实现Runna接口
实现run()方法,编写线程执行体
创建线程对象,调用start()方法启动线程
package 多线程;
//方法二:实现Runnable接口,重写run方法,执行线程需要丢入Runnable接口实现类,调用start开启线程
public class Create2 implements Runnable{
@Override
public void run() {
//run方法线程体
for(int i = 0;i<20;++i){
System.out.println("我在看代码--" + i);
}
}
public static void main(String[] args) {
//创建Runnable接口的实现类对象
Create2 create2 = new Create2();
//创建线程对象,通过线程对象来开启我们的线程,代理
Thread thread = new Thread(create2);
thread.start();
//new Thread(create2).start();//二者等价
for (int i = 0; i < 20; i++) {
System.out.println("我在学习多线程--" + i);
}
}
}
输出结果也为穿插输出
抢票实例:
package 多线程;
public class Create3 implements Runnable{
//票数
private int ticketNums = 10;
@Override
public void run() {
while (true){
if(ticketNums<=0){
break;
}
System.out.println(Thread.currentThread().getName() + "拿到了第" + ticketNums-- + "票");
}
}
public static void main(String[] args) {
Create3 ticket = new Create3();
new Thread(ticket, "小明").start();
new Thread(ticket, "老师").start();
new Thread(ticket, "黄牛党").start();
}
}
/*
黄牛党拿到了第10票
黄牛党拿到了第7票
黄牛党拿到了第6票
黄牛党拿到了第5票
小明拿到了第8票
小明拿到了第3票
老师拿到了第9票
老师拿到了第1票
小明拿到了第2票
黄牛党拿到了第4票
*/
龟兔赛跑实例:
package 多线程;
//龟兔赛跑模拟
public class Rabbit implements Runnable{
//胜利者
private static String winner;
public void run(){
for (int i = 0; i <= 100; i++) {
//模拟兔子休息
if(Thread.currentThread().getName().equals("兔子")&&i%10==0){
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//判断比赛是否结束
boolean flag = gameover(i);
if(flag){
break;
}
System.out.println(Thread.currentThread().getName() + "跑了" + i + "步");
}
}
//判断是否完成比赛
private boolean gameover(int steps){
//判断是否有胜利者
if(winner!=null){//已经存在胜利者了
return true;
}
if(steps>=100){
winner = Thread.currentThread().getName();
System.out.println("winner is " + winner);
return true;
}
return false;
}
public static void main(String[] args) {
Rabbit rabbit = new Rabbit();
new Thread(rabbit, "兔子").start();
new Thread(rabbit, "乌龟").start();
}
}
//无论怎样都是乌龟获胜
方法三:实现Callable接口
实现方法:
实现Callable接口,设置返回值
重写call方法,并抛出异常
创建目标对象
进入主函数......
package 多线程;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.concurrent.*;
//方法三:实现callable接口
/*
可以定义返回值
可以抛出异常
实现复杂
*/
public class TestCallable implements Callable<Boolean> {
private String url;
private String name;
public TestCallable(String url, String name) {
this.url = url;
this.name = name;
}
public Boolean call() {
WebDownloader webDownloader = new WebDownloader();
webDownloader.downloader(url, name);
System.out.println("下载了文件名为:" + name);
return true;
}
public static void main(String[] args) throws Exception, InterruptedException{
TestCallable t1 = new TestCallable("https://pic1.zhimg.com/80/v2-86c0da0f749a46a1a7a2c7b80465d530_720w.jpg?source=1940ef5c", "qzy.jpg");
TestCallable t2= new TestCallable("https://ts1.cn.mm.bing.net/th?id=OIP-C.5eGvoxrfiCR8-F954A0g2gAAAA&w=146&h=170&c=8&rs=1&qlt=90&o=6&dpr=1.25&pid=3.1&rm=2", "bqb.jpg");
TestCallable t3 = new TestCallable("https://ts1.cn.mm.bing.net/th?id=OIP-C.q5iRYT4Q_g_r7UBqAON9UwAAAA&w=146&h=170&c=8&rs=1&qlt=90&o=6&dpr=1.25&pid=3.1&rm=2", "xzc.jpg");
//创建执行服务:
ExecutorService ser = Executors.newFixedThreadPool(3);
//提交执行服务:
Future<Boolean> result1 = ser.submit(t1);
Future<Boolean> result2 = ser.submit(t2);
Future<Boolean> result3 = ser.submit(t3);
//获取结果:
boolean rs1 = result1.get();
boolean rs2 = result2.get();
boolean rs3 = result3.get();
//关闭服务
ser.shutdownNow();
}
}
class WebDownloader{
//下载方法
public void downloader(String url, String name){
try {
FileUtils.copyURLToFile(new URL(url), new File(name));
} catch (IOException e) {
System.out.println("IO异常,downloader方法出现问题");
}
}
}
/*
结果为:
下载了文件名为:bqb.jpg
下载了文件名为:xzc.jpg
下载了文件名为:qzy.jpg
*/