线程知识1

1. 什么是多线程

多线程允许我们"同时"执行多段代码.
- 进程:程序的集合
- 线程:一个进程包含多个线程,java默认两个线程:main和GC线程
- java并不能开启线程,它是运行在JVM虚拟机,不能操作硬件,它底层通过C语言,开启的
- 并发编程的本质是:充分利用资源
//获取CPU的核数
 //CPU密集型 IO 密集型
 System.out.println(Runtime.getRuntime().availableProcessors());

并发运行:线程是并发运行的,线程调度会统一规划CPU时间,将 CPU的时间划分为若干片段,然后尽可能的均匀分配给所有要并发运行的线程,每个线程在获得CPU时间片后,CPU就来运行它的任务,当时间片用完后,CPU会离开并执行获取到CPU时间片的线程,所以所有线程并非真正的"同时"运行着代码,而都是走走停停的,这种微观上走走停停,宏观上感觉是同时运行的。

  • CPU 单核 ,多个线程快速切换,其实是并发运行
  • CPU多核,多个线程同时运行,是并行

2. 线程的两种创建方式

第一种:继承Thread并重写run方法来定义线程任务

public class ThreadDemo1 {
	public static void main(String[] args) {
		Thread t1 = new MyThread1();
		Thread t2 = new MyThread2();
		/*
		 * 注意,启动线程不要调用run方法,而是要
		 * 调用start方法.
		 * 线程开始并发运行时会自动调用run方法.
		 */
		t1.start();
		t2.start();
		
	}
}
class MyThread1 extends Thread{
	public void run(){
		for(int i=0;i<1000;i++){
			System.out.println("你找谁?");
		}
	}
}
class MyThread2 extends Thread{
	public void run(){
		for(int i=0;i<1000;i++){
			System.out.println("马冬梅!!!");
		}
	}
}

注意:启动线程不要调用run方法,而是要调用start方法.
线程开始并发运行时会自动调用run方法.

第二种 实现Runnable接口单独定义线程任务

public class ThreadDemo2 {
	public static void main(String[] args) {
		//创建任务
		Runnable r1 = new MyRunnable1();
		Runnable r2 = new MyRunnable2();

		//创建线程
		Thread t1 = new Thread(r1);
		Thread t2 = new Thread(r2);

		t1.start();
		t2.start();
	}
}
class MyRunnable1 implements Runnable{
	public void run() {
		for(int i=0;i<1000;i++){
			System.out.println("你找谁?");
		}
	}
}
class MyRunnable2 implements Runnable{
	public void run() {
		for(int i=0;i<1000;i++){
			System.out.println("马冬梅!!!");
		}
	}
}

第三种 实现Callable接口,重写call方法

public class CalableDemo implements Callable<Boolean>{
	
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		CalableDemo cl1 = new CalableDemo();
		CalableDemo cl2 = new CalableDemo();
		CalableDemo cl3 = new CalableDemo();
		
		//执行服务
		ExecutorService es = Executors.newFixedThreadPool(3);
		
		//提交线程,返回值
		Future<Boolean> fu1 = es.submit(cl1);
		Future<Boolean> fu2 = es.submit(cl2);
		Future<Boolean> fu3 = es.submit(cl3);
		
		System.out.println(fu1.get()+" "+fu2.get()+" "+fu3.get());
		
		es.shutdown();
	}


	@Override
	public Boolean call() throws Exception {
		//可以抛出异常
		for(int i=0;i<20;i++){
			System.out.println(Thread.currentThread().getName()+":我是谁,我在哪!");
		}
		return true;
	}

}
//Callable的第二种开启方式
public class CallableDemo {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
       Mythread mythread = new Mythread();
       //FutureTask间接实现了Runnable接口
       FutureTask futureTask = new FutureTask(mythread);
       new Thread(futureTask,"A").start();
       new Thread(futureTask,"B").start();//有缓存,还是只输出一个"Call()"
       //get方法因为等待获取返回值,有可能造成阻塞,
       //把它写在最后一行,避免影响  其它;
       //或者 采用异步通信
       String string  = (String)futureTask.get();
        System.out.println(String);

    }
}
class Mythread implements  Callable<String>{

    @Override
    public String call() throws Exception {
        System.out.println("call()");
        return "123";
    }
}
3. 第一种创建线程的方式有两个不足:

1:由于java是单继承,这就导致若继承了Thread,就不能再继承其他类,在实际开发中非常不方便,因为无法重用其他类的某些方法.

2:由于继承Thread后重写run方法定义了线程要执行的任务,这就导致线程与线程要执行的任务有一个必然的耦合关系,不利于线程重用.

4. 第三种有两个好处

1.可以抛出异常
2.有返回值

拓展知识点:

程序是静态的,启动起来成了进程,进程是动态的,进程需要线程来执行任务

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值