多线程和JUC

进程

进程就是正在运行的程序,是系统进行资源分配和调用的独立单位。每一个进程都有他自己的内存空间和系统资源
多进程意义在于计算机可以执行多个任务,提高cpu使用率
我们在一边玩游戏,一边听音乐的时候,是cpu在做着程序间的高效切换让我们觉得是同时进行的
注意:很多多线程是模拟出来的,真正的多线程是指有多个cpu,即多核,如服务器。 如果是模拟出来的多线程,即在一个cpu的情况下,在同一时间点,cpu只能执行一个代码,因为切换的很快,所以就有同时执行的错觉

线程

线程是依赖于进程而存在的,在一个进程内又可以执行多个任务,而这每个任务我就可以看出是一个线程
线程:是程序的执行单元,执行路径。是程序使用cpu的最基本单位。
单线程:程序只有一条执行路径
多线程:程序有多条执行路径
多线程意义在于提高应用程序的使用率。不是提高程序的执行速度
程序的执行其实都是在抢cpu的资源,cpu的执行权
多个进程是抢这个资源,而其中的某一个进程如果执行路径比较多,就会有更高的几率抢到cpu的执行权,所以线程的执行有随机性
注意:
并行和并发的区别:
前者:逻辑上同时发生,指在某一个时间段同时运行多个程序
CPU多核,多个线程可以同时执行线程池
后者:物理上同时发生,指在某一个时间点同时运行多个程序
CPU单核,cpu只能执行一个代码,因为切换的很快,所以就有同时执行的错觉
并发编程本质就是充分利用CPU的资源

java程序的运行原理

由java命令启动jvm,jvm启动就相当于启动了一个进程,接着有这个该进程创建了一个主线程去调用main()方法
那么jvm虚拟机的启动是多线程,因为垃圾回收线程也要先启动,否则很容易出现内存溢出。主线程加垃圾回收线程
小结:
线程就是独立的执行路径;
在程序运行时,即使没有自己创建线程,后台也会有多个线程,如主线程,gc线程;
main()成为主线程,为系统的入口,用于执行整个程序;
在一个进程中,如果开辟了多个线程,线程的运行由调度器(CPU)安排调度,调度器是与操作系统紧密相关,先后顺序是不能人为的干预的;
对同一份资源操作时,会存在资源抢夺的问题,需要加入并发控制;
线程会带来额外的开销,如CPU调度时间,并发控制开销;
每个线程在自己的工作内存交互,内存控制不当会造成数据不一致;

如何实现多线程的程序?

继承Thread类:
子类继承Thread类具备多线程能力
启动线程:子类对象.start()方法
不建议使用:避免OOP单继承局限性

import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.IOException;
import java.net.URL;

public class ThrendDemo extends Thread{
    //src="http://iflyssedata.oss-cn-shanghai.aliyuncs.com/images/20191101021614.png"
    //src="http://iflyssedata.oss-cn-shanghai.aliyuncs.com/images/20201015024451.png"
    //src="http://iflyssedata.oss-cn-shanghai.aliyuncs.com/images/20190902094518.png"

    String url;
    String name;
    public ThrendDemo(String url,String name){
        this.url=url;
        this.name=name;
    }
    @Override
    public void run() {
        DownWeb downWeb = new DownWeb();
        downWeb.downLoader(url,name);

        System.out.println("下载了文件名为"+name);
    }

    public static void main(String[] args) {
        ThrendDemo th1 = new ThrendDemo("http://iflyssedata.oss-cn-shanghai.aliyuncs.com/images/20191101021614.png","1.jpg");
        ThrendDemo th2 = new ThrendDemo("http://iflyssedata.oss-cn-shanghai.aliyuncs.com/images/20201015024451.png","2.jpg");
        ThrendDemo th3 = new ThrendDemo("http://iflyssedata.oss-cn-shanghai.aliyuncs.com/images/20190902094518.png","3.jpg");

        th1.start();
        th2.start();
        th3.start();

    }
}

class DownWeb{
    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接口。 那个类然后实现了run方法。 然后可以分配类的实例,在创建Thread时作为参数传递,并启动
实现接口方式的好处
可以避免由于java单继承带来的局限性;适合多个相同程序的代码去处理同一个资源的情况,把线程同程序的代码,数据有效分离,较好的体现了面向对象的设计思想
为什么要重写run()方法?
run()里面封装的是被线程执行的代码
启动线程对象用的是哪个方法?
start()
run()和start()方法的区别?
run()直接调用的仅仅是普通方法
start()先启动线程,再由jvm调用run()
实现接口Runnable具有多线程能力
启动线程:new Thread(传入目标对象).start()
推荐使用:避免单继承局限性,灵活方便,方便同一个对象被多个线程使用

import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.IOException;
import java.net.URL;

public class ThrendDemo implements Runnable{

    String url;
    String name;
    public ThrendDemo(String url,String name){
        this.url=url;
        this.name=name;
    }
    @Override
    public void run() {
        DownWeb downWeb = new DownWeb();
        downWeb.downLoader(url,name);

        System.out.println("下载了文件名为"+name);
    }

    public static void main(String[] args) {
        ThrendDemo th1 = new ThrendDemo("http://iflyssedata.oss-cn-shanghai.aliyuncs.com/images/20200528052009.png","4.jpg");
        ThrendDemo th2 = new ThrendDemo("http://iflyssedata.oss-cn-shanghai.aliyuncs.com/images/20191105020544.png","5.jpg");
        ThrendDemo th3 = new ThrendDemo("https://ss0.bdstatic.com/94oJfD_bAAcT8t7mm9GUKT-xh_/timg?image&quality=100&size=b4000_4000&sec=1603600907&di=62c16889d83b7e6742012de55df48d04&src=http://meitu.qqzong.com/www.52520qq.com/uploads/allimg/181106/003G51110-0.jpg","6.jpg");

//        th1.start();
//        th2.start();
//        th3.start();

        new Thread(th1).start();
        new Thread(th2).start();
        new Thread(th3).start();

    }
}

class DownWeb{
    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异常,下载失败");
        }
    }

}

实现Callable接口
1.实现Callable接口,需要返回值类型
2.重写call方法,需要抛出异常
3.创建目标对象
4.创建执行服务:
5.提交执行
6.获取结果
7.关闭服务

import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.concurrent.*;

public class ThrendDemo implements Callable<Boolean> {
    String url;
    String name;
    public ThrendDemo(String url,String name){
        this.url=url;
        this.name=name;
    }
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ThrendDemo th1 = new ThrendDemo("http://iflyssedata.oss-cn-shanghai.aliyuncs.com/images/20200528052009.png","4.jpg");
        ThrendDemo th2 = new ThrendDemo("http://iflyssedata.oss-cn-shanghai.aliyuncs.com/images/20191105020544.png","5.jpg");
        ThrendDemo th3 = new ThrendDemo("https://ss0.bdstatic.com/94oJfD_bAAcT8t7mm9GUKT-xh_/timg?image&quality=100&size=b4000_4000&sec=1603600907&di=62c16889d83b7e6742012de55df48d04&src=http://meitu.qqzong.com/www.52520qq.com/uploads/allimg/181106/003G51110-0.jpg","6.jpg");
//        4.创建执行服务:
        ExecutorService executorService =Executors.newFixedThreadPool(3);
//        5.提交执行
        Future<Boolean> future1= executorService.submit(th1);
        Future<Boolean> future2= executorService.submit(th2);
        Future<Boolean> future3= executorService.submit(th3);
//        6.获取结果
        future1.get();
        future2.get();
        future3.get();
//        7.关闭服务
        executorService.shutdownNow();
    }
    @Override
    public Boolean call() throws Exception {
      DownWeb downWeb = new DownWeb();
      downWeb.downLoader(url,name);
        System.out.println("下载文件名为"+name);
      return true;
    }
}
class DownWeb{
    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异常,下载失败");
        }
    }
}

匿名内部类(重写run)

 Thread thread = new Thread(new Runnable() {
            public void run() {
                
            }
        });
        
        thread.start();

由于线程是依赖进程而存在,所以应该先创建一个进程出来,而进程是系统创建的,所以我们应该去调用系统功能创建一个进程。java是不能直接调用系统功能的,依赖于c/c++去调用系统功能创建进程,然后java去调用这样的东西
(Unsafe类 java无法操作内存,java可以调用c++ native c++可以操作内存)
(1)如何设置线程对象的名称?
public final String getName();获取线程的名称

@Override
	public void run() {
		// TODO Auto-generated method stub
		for(int i=0;i<200;i++) {
			System.out.println(getName()+"点赞"+i);
		}
	}
Thread-0点赞0
Thread-0点赞1
Thread-0点赞2
Thread-0点赞3
Thread-0点赞4
Thread-1点赞0

(2)如何设置线程对象的名称
public final void setName(String name)

//默认无参构造+setName()来设置线程名称
//		//创建两个线程对象
//		MyThreadDemo myThreadDemo1 = new MyThreadDemo();
//		MyThreadDemo myThreadDemo2 = new MyThreadDemo();
//		//设置线程名称
		myThreadDemo1.setName("线程一");
		myThreadDemo2.setName("线程二");
//		//线程启动
//		myThreadDemo1.start();
//		myThreadDemo2.start();
		
		//通过有参构造来设置线程名称
		MyThreadDemo myThreadDemo3 =new MyThreadDemo("线程三");
		MyThreadDemo myThreadDemo4 = new MyThreadDemo("线程四");
		
		myThreadDemo3.start();
		myThreadDemo4.start();
		
线程二点赞9
线程一点赞0
线程一点赞1
线程一点赞2
线程一点赞3

针对不是Thread类的子类中来获取线程对象的名称?
public static Thread currentThread()
Thread.currentThread().getName()
(3)线程有个默认优先级就是5
如何设置优先级?(1最低优先级,10最高优先级,优先级用数字表示,范围从1~10)
java使用的是抢占式调度模型 优先让优先级高的线程使用cpu,如果线程的优先级相同,那么会随机选择一个,优先级高的线程获取的cpu时间片相对多一些
线程优先级高仅仅表示线程获取的cpu时间片的几率高,但是要在运行次数多的时候才会看到比较好的效果
public final int getPriority();返回线程对象的优先级
public final void setPriority(int newPriority)//更改线程的优先级
注意:优先级的设定建议在start()调度前;优先级低只是意味着获得调度的概率低,并不是优先级低就不会被调用了,这都是看cpu的调度

public class ThreadPriority implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());
    }

    public static void main(String[] args) {
        ThreadPriority threadPriority = new ThreadPriority();

        Thread thread1 = new Thread(threadPriority);
        Thread thread2 = new Thread(threadPriority);
        Thread thread3 = new Thread(threadPriority);
        Thread thread4= new Thread(threadPriority);
        Thread thread5= new Thread(threadPriority);
        Thread thread6 = new Thread(threadPriority);

        thread1.setPriority(8);
        thread1.start();

  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值