多线程
1.线程就是独立的执行路径
2.main()称之为主线程,为系统的入口,用于执行整个程序
3.在一个进程中,如果开辟了多个线程,线程的运行由调度器安排调度,调度器是与操作系统紧密相关的,先后顺序是不能人为的干预的
4.对同一份资源操作是,会存在资源抢夺的问题,需要加入并发控制
5.线程会带来额外的开销,如cpu调度时间,并发控制开销
6.每个线程在自己的工作内存交互,内存控制不当会造成数据不一致
线程创建
Thread.class
1、自定义线程类继承Thread类
2、重写run()方法,编写线程执行体
3、创建线程对象,调用start()方法启动线程
注:线程开启不一定立即执行,根据cpu调度安排
public class TestThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 2000; i++) {
System.out.println("run线程-------------");
}
}
public static void main(String[] args) {
//main线程,主线程
TestThread testThread = new TestThread();
testThread.start();
for (int i = 0; i < 2000; i++) {
System.out.println("main线程++++++++++++++");
}
}
}
例子,网络图片下载
public class TestThread2 extends TestThread{
private String name;
private String url;
//构造器
TestThread2(String url,String name){
this.name = name;
this.url = url;
}
//线程执行体
@Override
public void run() {
WebDownloader webDownloader = new WebDownloader();
webDownloader.downloader(url,name);
System.out.println(name);
}
public static void main(String[] args) {
TestThread2 t1 = new TestThread2("https://image.baidu.com/search/detail?ct=503316480&z=undefined&tn=baiduimagedetail&ipn=d&word=jpg%E5%9B%BE%E7%89%87&step_word=&ie=utf-8&in=&cl=2&lm=-1&st=undefined&hd=undefined&latest=undefined©right=undefined&cs=1671943955,3320345726&os=749330975,400155190&simid=46899987,1043920955&pn=0&rn=1&di=7060663421280190465&ln=1424&fr=&fmq=1648131319030_R&fm=&ic=undefined&s=undefined&se=&sme=&tab=0&width=undefined&height=undefined&face=undefined&is=0,0&istype=0&ist=&jit=&bdtype=0&spn=0&pi=0&gsm=0&objurl=https%3A%2F%2Fss0.baidu.com%2F-Po3dSag_xI4khGko9WTAnF6hhy%2Fbaike%2Fpic%2Fitem%2F9825bc315c6034a8cda67260c11349540823768f.jpg&rpstart=0&rpnum=0&adpicid=0&nojc=undefined&dyTabStr=MCwzLDIsNiw0LDUsNyw4LDEsOQ%3D%3D","1.jpg");
TestThread2 t2 = new TestThread2("https://image.baidu.com/search/detail?ct=503316480&z=undefined&tn=baiduimagedetail&ipn=d&word=jpg%E5%9B%BE%E7%89%87&step_word=&ie=utf-8&in=&cl=2&lm=-1&st=undefined&hd=undefined&latest=undefined©right=undefined&cs=3496781279,3725135679&os=3411366938,3533778484&simid=3264064304,3725877970&pn=7&rn=1&di=7060663421280190465&ln=1424&fr=&fmq=1648131524239_R&fm=&ic=undefined&s=undefined&se=&sme=&tab=0&width=undefined&height=undefined&face=undefined&is=0,0&istype=0&ist=&jit=&bdtype=0&spn=0&pi=0&gsm=0&objurl=https%3A%2F%2Fgimg2.baidu.com%2Fimage_search%2Fsrc%3Dhttp%253A%252F%252Fwww.erdangjiade.com%252Fproject%252Fimages%252Ffb9b6a26f2f2e14cb42ff2ceeb144cb2.jpg%26refer%3Dhttp%253A%252F%252Fwww.erdangjiade.com%26app%3D2002%26size%3Df9999%2C10000%26q%3Da80%26n%3D0%26g%3D0n%26fmt%3Dauto%3Fsec%3D1650723522%26t%3D3c48e05f71ca421943e84fd890b202f8&rpstart=0&rpnum=0&adpicid=0&nojc=undefined&dyTabStr=MCwzLDIsNiw0LDUsNyw4LDEsOQ%3D%3D","2.jpg");
TestThread2 t3 = new TestThread2("https://image.baidu.com/search/detail?ct=503316480&z=undefined&tn=baiduimagedetail&ipn=d&word=jpg%E5%9B%BE%E7%89%87&step_word=&ie=utf-8&in=&cl=2&lm=-1&st=undefined&hd=undefined&latest=undefined©right=undefined&cs=3134447943,3951842718&os=3545318994,2194840880&simid=4269224249,590545950&pn=1&rn=1&di=7060663421280190465&ln=1424&fr=&fmq=1648131524239_R&fm=&ic=undefined&s=undefined&se=&sme=&tab=0&width=undefined&height=undefined&face=undefined&is=0,0&istype=0&ist=&jit=&bdtype=0&spn=0&pi=0&gsm=0&objurl=https%3A%2F%2Fgimg2.baidu.com%2Fimage_search%2Fsrc%3Dhttp%253A%252F%252Fdogame.com.cn%252Fbbs%252Fattachments%252Fday_150227%252F15022720201f0cf31d827b4a84.jpg%26refer%3Dhttp%253A%252F%252Fdogame.com.cn%26app%3D2002%26size%3Df9999%2C10000%26q%3Da80%26n%3D0%26g%3D0n%26fmt%3Dauto%3Fsec%3D1650723522%26t%3D42aa03881194a732fd82cf34021b6258&rpstart=0&rpnum=0&adpicid=0&nojc=undefined&dyTabStr=MCwzLDIsNiw0LDUsNyw4LDEsOQ%3D%3D","3.jpg");
t1.start();
t2.start();
t3.start();
}
}
class WebDownloader{
public void downloader(String url,String name){
try {
FileUtils.copyURLToFile(new URL(url),new File(name));
} catch (IOException e) {
e.printStackTrace();
System.out.println("IO异常");
}
}
}
运行结果
Runnable接口
1、定义MyRunnable类实现Runnable接口
2、实现run()方法,编写线程执行体
3、创建线程对象,调用start()方法启动线程
推荐使用Runnable对象,避免单继承局限性,灵活方便,方便同一个对象被多个线程使用
public class TestThread2 implements Runnable{
public void run() {
for (int i = 0; i < 2000; i++) {
System.out.println("run线程-------------");
}
}
public static void main(String[] args) {
//创建Runnable接口的实现类对象
TestThread2 testThread2 = new TestThread2();
//创建线程对象,通过线程对象来开启我们的线程,代理
new Thread(testThread2).start();
for (int i = 0; i < 2000; i++) {
System.out.println("main线程++++++++++++++");
}
}
}
多个线程操作同一个资源的情况下,线程不安全,数据紊乱
//多个线程同时操作一个对象
//买火车票的例子
public class ThreadTest3 implements Runnable {
//票数
private int ticketNums = 10;
public void run() {
while (true){
if (ticketNums<=0){
break;
}
//模拟延迟
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"-->拿到了第"+ticketNums--+"票");
}
}
public static void main(String[] args) {
ThreadTest3 ticket = new ThreadTest3();
new Thread(ticket,"user1").start();
new Thread(ticket,"user2").start();
new Thread(ticket,"user3").start();
}
}
返回结果:第四张票,被三个用户都拿到了,这样是错误的结果
Callable接口