文章目录
- JAVA多线程——创建线程
- 继承Thread类
- **创建Thread匿名子类的方式也可以创建线程**
- Thread类有关的常用方法
- 实现Runnable接口
- 并发问题
- 龟兔赛跑案例
- 实现Callale接口
JAVA多线程——创建线程
继承Thread类
- 自定义一个线程类继承Thread类
- 重写run方法,编写线程执行体
- 创建线程对象,调用start()方法启动线程
- 不建议使用,java是单继承有局限性
package com.peng.demon01;
import javax.swing.*;
//创建线程方式一:继承Threaf类,重写run方法,调用start开启线程
public class TestThread01 extends Thread{
@Override
public void run() {
//线程体
for (int i = 0; i < 100; i++) {
System.out.println("打王者荣耀"+i);
}
}
public static void main(String[] args) {//main()线程,主线程
//开启另外一个线程
//创建一个线程对象
TestThread01 testThread01 = new TestThread01();
//调用start开启线程
testThread01.start();//start()方法的作用:1,启动当前线程 2,调用当前线程的run()方法
for (int i = 0; i < 1000; i++) {//由主线程运行
System.out.println("不要打英雄联盟"+i);
}
}
}
两个线程交替执行
线程开启并不一定立即执行,由CPU调度执行
用多线程实现下载网图
package com.peng.demon01;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
//实现多线程同步下载图片
public class TestThread02 extends Thread{
private String url;//地址
private String name;//图片名
// 构造器
public TestThread02(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);
}
public static void main(String[] args) {
//线程体
//创建线程对象
TestThread02 testThread01 = new TestThread02("http://www.xinhuanet.com/photo/2020-08/26/1126412315_15983723897731n.jpg",",新华网图片1.jpg");
TestThread02 testThread02 = new TestThread02("http://www.xinhuanet.com/photo/2020-08/26/1126412315_15983723898911n.jpg",",新华网图片2.jpg");
TestThread02 testThread03 = new TestThread02("http://www.xinhuanet.com/photo/2020-08/25/1126412104_15983627450851n.jpg",",新华网图片3.jpg");
TestThread02 testThread04 = new TestThread02("http://www.xinhuanet.com/photo/2020-08/25/1126412104_15983627451171n.jpg",",新华网图片4.jpg");
//启动线程
testThread01.start();
testThread02.start();
testThread03.start();
testThread04.start();
}
}
//下载器
class WebDownloader{
//下载方法
public void downloader(String url,String name){
try {//捕获异常
// FileUtils是一个工具类,copyURLToFile是一个方法,方法的作用是把网络资源的地址变成文件
FileUtils.copyURLToFile(new URL(url),new File(name));
} catch (IOException e) {
e.printStackTrace();
System.out.println("IO异常,downloader方法出现问题");
}
}
}
创建Thread匿名子类的方式也可以创建线程
package com.work;
//继承Thread类创建线程
public class Work1 {
public static void main(String[] args) {
new Thread(){
@Override
public void run() {
for (int i = 0; i <100 ; i++) {
if (i % 2==0){
System.out.println(Thread.currentThread().getName() +" " +i);
}
}
}
}.start();
new Thread(){
@Override
public void run() {
for (int i = 0; i <100 ; i++) {
if (i % 2!=0){
System.out.println(Thread.currentThread().getName()+" " +i);
}
}
}
}.start();
}
}
Thread类有关的常用方法
start():启动线程,并执行对象的run()方法
run() :线程在被调度时执行的操作
currentThread():静态方法,返回执行当前代码的线程
getName():获取当前线程的名字
setName():设置当前线程的名字
利用构造方法也可以给线程命名
yield():释放CPU的执行权
join():如果在线程A中调用B线程的join(),线程A将会进入阻塞状态,等线程B执行完毕后才会继续执行A线程
sleep() :让线程休眠
isAlive() :判断当前线程是否存活
package com.peng.demon01;
/*测试Thread类的方法
start():启动线程,并执行对象的run()方法
run() :线程在被调度时执行的操作
currentThread():静态方法,返回执行当前代码的线程
getName():获取当前线程的名字
setName():设置当前线程的名字
yield():释放CPU的执行权
join():如果在线程A中调用B线程的join(),线程A将会进入阻塞状态,等线程B执行完毕后才会继续执行A线程
*/
public class ThreadMethodTest {
public static void main(String[] args) {
Thread1 thread1 = new Thread1("金鱼姬");
//thread1.setName("狂铁");//设置当前线程的名字
thread1.start();
//给主线程设置名字
// 返回执行当前代码的线程
Thread.currentThread().setName("主线程");
for (int i = 0; i <100 ; i++) {
if (i % 2==0){
System.out.println(Thread.currentThread().getName()+"; "+i);
}
if (i==20)
try {
thread1.join();//当主线程执行到20时开始执行另一个线程
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//判断当前线程是否存活 false
System.out.println(thread1.isAlive());
}
}
class Thread1 extends Thread{
@Override
public void run() {
for (int i = 0; i <100 ; i++) {
if (i % 2==0){
// try {
// sleep(1000);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
System.out.println(Thread.currentThread().getName()+"; "+i);
}
//if (i%20==0);
// yield();//释放CPU的执行权
}
}
//利用构造方法也可以给线程命名
public Thread1(String name){
super(name);
}
}
实现Runnable接口
- 定义MyRunnable类实现Runnable接口
- 实现run()方法,编写线程实行体
- 创建线程对象,调用start()方法启动线程
推荐使用实现Runnable接口,可以避免单继承局限性,灵活方便,方便统一个对象被多个线程使用
package com.peng.demon01;
//创建线程方式2,:实现Runnable接口,重写run方法,执行线程需要丢入Runnable接口的实现类,调用start开启线程
public class TestThread03 implements Runnable{
@Override
public void run() {
//线程体
for (int i = 0; i <200; i++) {
System.out.println("打王者荣耀"+i);
}
}
public static void main(String[] args) {//main()线程,主线程
//创建一个Runnable接口的实现类的对象
TestThread03 testThread03 = new TestThread03();
//创建线程对象,通过线程对象来开启线程
// Thread new = new Thread(testThread03);
//new Thread.start();
new Thread(testThread03).start();
for (int i = 0; i < 1000; i++) {
System.out.println("不要打英雄联盟"+i);
}
}
}
并发问题
多个线程操作同一个资源的情况下,线程不安全,数据紊乱。
package com.peng.demon01;
//多个线程同时操作同一个对象 买火车票的例子
public class TestThread04 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) {
//创建Runnable实现类的对象
TestThread04 ticket = new TestThread04();
//开启多个线程
new Thread(ticket,"狂铁").start();
new Thread(ticket,"后羿").start();
new Thread(ticket,"达摩").start();
}
}
龟兔赛跑案例
package com.peng.demon01;
//模拟龟兔赛跑
public class Race implements Runnable {
//定义一个胜利者
private static String winner;
@Override
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==true){//如果比赛结束,就停止程序
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) {
//开启线程
Race race = new Race();
new Thread(race,"兔子").start();
new Thread(race,"乌龟").start();
}
}
实现Callale接口
实现Callale接口的好处
- 可以定义返回值
- 可以抛出异常
package com.peng.demon02;
import com.peng.demon01.TestThread02;
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;
}
@Override
public Boolean call() {
//线程执行体
WebDownloader webDownloader = new WebDownloader();
webDownloader.downloader(url,name);
System.out.println("下载了文件名为"+name);
return true;
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
//线程体
//创建线程对象
TestCallable testCallable01 = new TestCallable("http://www.xinhuanet.com/photo/2020-08/26/1126412315_15983723897731n.jpg",",新华网图片1.jpg");
TestCallable testCallable02 = new TestCallable("http://www.xinhuanet.com/photo/2020-08/26/1126412315_15983723898911n.jpg",",新华网图片2.jpg");
TestCallable testCallable03 = new TestCallable("http://www.xinhuanet.com/photo/2020-08/25/1126412104_15983627450851n.jpg",",新华网图片3.jpg");
TestCallable testCallable04 = new TestCallable("http://www.xinhuanet.com/photo/2020-08/25/1126412104_15983627451171n.jpg",",新华网图片4.jpg");
//启动线程
//创建执行服务 ExecutorService,Executors是两个类 FixedThreadPool线程池
ExecutorService ser = Executors.newFixedThreadPool(3);
//提交执行 把三个线程提交上去,然后返回三个返回值,三个返回值都是true
Future<Boolean> result1 = ser.submit(testCallable01);
//submit方法:执行任务,有返回值,一般用来执行Callable接口
Future<Boolean> result2 = ser.submit(testCallable02);
Future<Boolean> result3 = ser.submit(testCallable03);
//获取结果 获得返回值,返回值类型为boolean,返回值名字为r1,r2,r3
boolean r1 = result1.get();
boolean r2 = result1.get();
boolean r3 = result1.get();
System.out.println(r1);//true
System.out.println(r2);//true
System.out.println(r3);//true
//关闭服务
ser.shutdownNow();
}
//下载器
class WebDownloader {
//下载方法
public void downloader(String url, String name) {
try {//捕获异常
// FileUtils是一个工具类,copyURLToFile是一个方法,方法的作用是把网络资源的地址变成文件
FileUtils.copyURLToFile(new URL(url), new File(name));
} catch (IOException e) {
e.printStackTrace();
System.out.println("IO异常,downloader方法出现问题");
}
}
}
}