java--线程

什么是进程

  • 一个应用程序对应一个进程。比如启动一个QQ,就是启动了一个进程。

什么是线程

  • 线程是进程的子集,一个进程可以启动多个线程,是进程中实际运作的最小单位。

并行

  • 并行是指多个cpu实例或者多台机器同时执行一段处理逻辑,是真正的同时。

并发

  • 通过CPU调度算法,不停的切换线程,使用户看起来是在同时进行,但在站在CPU的角度,并不是同时进行的。

多线程产生的原因

  • 在多线程没有产生之前,计算机只能一步一步的顺序执行。随着计算机的发展,计算机需要处理的任务越来越多,这就需要计算机并发的去执行多个任务,单线程就无法满足这种需求,所以就产生的多线程。多线程可以更好的利用计算机资源,可以在一个线程等待的时候,其它线程利用计算机资源处理其它的任务,减少计算机资源的浪费。

线程的生命周期

多线程的生命周期变化图

  1. new
    新建状态。当创建一个线程对象,此时该线程就处于新建状态。比如Thread thread = new MyThread()。
  2. Runnable
    就绪状态。当一个线程对象调用start()方法的时候,线程就处于就绪状态,需要等待CPU的调度。
  3. Running
    运行状态。线程处于就绪状态后,说明该线程已经完全准备好了,等待CPU的调度。计算机根据CPU的调度算法调用就绪状态的线程,当某个线程被CPU调用后,线程就处于了运行状态。
  4. Blocked
    阻塞状态。线程在运行期间,可能会由于某种原因而处于阻塞状态,此时线程需要从阻塞状态变为就绪状态,才能被cpu调度运行。线程进入运行状态的入口只有一个,那就是就绪状态。 产生阻塞的原因可分为以下几种:
    4.1 等待阻塞:线程执行wait()方法,使线程进入等待阻塞状态。
    4.2 同步阻塞:线程在获取synchronized同步锁时,由于synchronized锁已被其它线程占用,就会进入同步阻塞状态。
    4.3 其它阻塞:通过调用线程的sleep()、join()方法或者是发出其它的I/O请求时,线程就会进入到阻塞状态,当sleep()/join()方法执行完毕或I/O完成时,线程就会由阻塞状态转变为就绪状态,重新等待CPU的调度。
  5. Dead
    死亡状态:当线程执行完毕或者异常退出run()方法,线程的生命周期就结束了。

创建线程的方法

  • 继承Thread类,重写run()方法。
package cn.Steven.sf;

public class ThreadTest{
   public static void main(String[] args) {
   	MyThread myThread1 = new MyThread();
   	myThread1.setName("myThread1");
   	MyThread myThread2 = new MyThread();
   	myThread2.setName("myThread2");
   	myThread1.start();
   	myThread2.start();
   	
   }

}

class MyThread extends Thread {
   @Override
   public void run() {
   	System.out.println(Thread.currentThread().getName() + "is running...");
   }
} 
  • 实现Runnable接口,重写run()方法
 package cn.Steven.sf;

public class RunnableTest {

	public static void main(String[] args) {
		MyRunnable myRunnable = new MyRunnable();
		Thread  thread1 = new Thread(myRunnable);
		thread1.setName("myRunnable1");
		Thread  thread2 = new Thread(myRunnable);
		thread2.setName("myRunnable2");
		thread1.start();
		thread2.start();
	}
}

class MyRunnable implements Runnable {

	@Override
	public void run() {
		System.out.println(Thread.currentThread().getName() + " is running...");
	}
	
}
  • 首先实现Callable接口,重写run()方法,然后使用FutureTask类来包装一下Callable接口的实现类,并且将这个包装过后的对象传入到Thread的构造方法中,这样就可以创建一个线程了。
package cn.Steven.sf;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class CallableTest {
   public static void main(String[] args) {
   	MyCallable myCallable = new MyCallable();
   	FutureTask<Integer> futureTask = new FutureTask<>(myCallable);
   	Thread thread = new Thread(futureTask);
   	thread.start();
   	try {
   		Integer sum = futureTask.get();
   		System.out.println("sum===" + sum);
   	} catch (InterruptedException | ExecutionException e) {
   		e.printStackTrace();
   	}
   }

}

class MyCallable implements Callable<Integer> {
   
   private Integer i =0;

   @Override
   public Integer call() throws Exception {
   	int sum = 0;
   	for(; i <= 10; i++) {
   		sum += i;
   	}
   	System.out.println(Thread.currentThread().getName() + " is running...");
   	return sum;
   }
   
}

线程中的几种常见方法

  • yield()
    使线程暂时退让CPU的使用权,让给其它线程抢占CPU,但是当前线程仍然处于就绪状态,仍有机会被CPU调度。所以yield()不可能让较低优先级的线程获取CPU占有权。
  • sleep()
    使线程进入休眠状态,参数为毫秒值。与yield()方法不同,该方法用户可以知道线程的休眠时间,此时线程会进入阻塞状态,所以低优先级的线程有机会获取CPU的占有权,但是此线程不会释放自身锁。
  • join()
    放弃当前线程的执行,让另一个线程执行。可以传入一个参数,表示让另一个线程执行多久。
public static void main(String[] args) {
   	Thread thread1 = new Thread();
   	thread1.start();
   	thread1.join();
   }

上面这段代码表示,main线程放弃CPU控制权,等待thread1执行完毕后,再执行main()方法,达到了同步的作用。如果在join()方法里面参数一个10,则表示main线程等待thread1线程执行10毫秒后,继续和thread1线程抢占CPU。需要注意的是join(0)和join()是一样的效果,表示无限的等待下去,直到thread1线程执行完毕。

  • wait()
    让线程进行等待,进入到阻塞状态,等待其它线程的唤醒,与sleep()方法不同,此时线程会释放自身锁。
  • notify/notifyall()
    唤醒其它的线程,让线程进入到就绪状态。通常和wait()方法用于协调多个线程对共享数据的存取,所以必须在synchronized语句块内使用。

Example

package cn.Steven.sf;

public class SynchExample implements Runnable {
   private int count = 0;

   @Override
   public void run() {
   	Thread.yield();
   	try {
   		Thread.sleep(300);
   		domore();
   	} catch (InterruptedException e) {
   		e.printStackTrace();
   	}

   }

   private void domore() throws InterruptedException {
   	synchronized (this) {
   		for (int i = 0; i < 5; i++) {
   			System.out.println(Thread.currentThread().getName() + ":" + (count++));
   			// 此时下面的if判断代码必须和主方法中的join()方法分开使用,不然会造成线程死锁。
   			if (i == 2) {
   				this.wait();
   			}
   			this.notifyAll();
   		}
   	}
   }

   public static void main(String[] args) throws InterruptedException {
   	SynchExample myrunnable = new SynchExample();
   	Thread thread1 = new Thread(myrunnable, "Thread1");
   	Thread thread2 = new Thread(myrunnable, "Thread2");
   	thread1.start();
   	/**
   	 * join的意思是使得放弃当前线程的执行,并返回对应的线程,例如下面代码的意思就是:
   	 * 程序在main线程中调用thread1线程的join方法,则main线程放弃CPU控制权,并返回thread1线程继续执行直到线程thread1执行完毕
   	 * 所以结果是thread1线程执行完后,才到主线程执行,相当于在main线程中同步thread1线程,thread1执行完了,main线程才有执行的机会
   	 */
   	thread1.join();
   	thread2.start();
   }
}


最后,请思考一个问题:下面的代码,输出的是Runnable接口中的run()方法还是Thread类中的run()方法?欢迎评论区留言~~~

package cn.Steven.sf;

public class MyThreadTest {

   public static void main(String[] args) {
       for (int i = 0; i < 100; i++) {
           System.out.println(Thread.currentThread().getName() + " " + i);
           if (i == 30) {
               Runnable myRunnable = new MyRunnable2();
               Thread thread = new MyThread2(myRunnable);
               thread.start();
           }
       }
   }
}

class MyRunnable2 implements Runnable {
   private int i = 0;

   @Override
   public void run() {
       System.out.println("in MyRunnable run");
       for (i = 0; i < 100; i++) {
           System.out.println(Thread.currentThread().getName() + " " + i);
       }
   }
}

class MyThread2 extends Thread {

   private int i = 0;
   
   public MyThread2(Runnable runnable){
       super(runnable);
   }

   @Override
   public void run() {
       System.out.println("in MyThread run");
       for (i = 0; i < 100; i++) {
           System.out.println(Thread.currentThread().getName() + " " + i);
       }
   }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值