多线程
1.方式一:继承Thread类
问题1
我们不能通过对象直接调用run()的方法启动线程
只有start才可以启动线程。
问题2
再启动一个线程,遍历1-100以内的偶数?
不可以让已经start()的线程去执行,会报IllegalThreadStateException的异常;
我们需要重新创建一个线程的对象去执行
/**
* 多线程的创建,方式一:继承与Thread类
* 1.创建一个继承与Thread类的子类
* 2.重写Thread类的run方法 -->将此线程执行的操作声明在run方法中
* 3.创建Thread类的子类的对象
* 4.通过此对象调用start()
*
* 例子:遍历100以内的所有的偶数
*/
class MyThread extends Thread{
2.方式二:实现Runnable接口
package Thread;
/**
* <h5>描述:创建多线程的方式二:实现Runnable接口</h5>
* 1.创建一个实现了Runnable接口的类
* 2.实现类去实现Runnable中的抽象方法:run()
* 3.创建实现类的对象
* 4.将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象
* 5.通过Thread类的对象调start()
*/
class MThread implements Runnable{
3.比较两种创建多线程的方式
开发中:优先选择实现Runnab的方式
原因:1.实现的方式没有类的单继承的局限性。
2.实现的方式更适合来处理多个线程有共享数据的情况。
联系:Thread的类本身也实现了Runnable。
相同点:两种方式都不需要重写run方法。
4.方式三:实现Callable接口(JDK5.0新增)
package Thread;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
/**
* <h5>描述:</h5>
* 实现Callable接口
*/
public class ThreadNew {
public static void main(String[] args) {
NumThread n1=new NumThread();
FutureTask f1 = new FutureTask(n1);
try {
//get方法的返回值即为FutureTask构造器参数Callable实现类重写的call方法的返回值
Object sum = f1.get();
System.out.println(sum);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
new Thread(f1).start();
}
}
class NumThread implements Callable{
5.使用线程池(JDK5.0新增)
package Thread;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
/**
* <h5>描述:</h5>
* 创建线程的方式四:使用线程池
*/
class NumberThread implements Runnable{
二.Thread常用的方法
1.Thread.currentThread().setName()
Thread.currentThread().getName()
设置并获取当前线程的名字
public class ThreadMethodText {
public static void main(String[] args) {
HelloThread t1=new HelloThread();
t1.setName("线程一");
t1.start();
Thread.currentThread().setName("主线程");
for (int i = 0; i < 100; i++) {
if (i%2==0){
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
}
class HelloThread extends Thread{
2.yield
释放执行权,线程让步
3.join
在线程a中调用线程b的join(),此时线程a就进入阻塞状态,直到线程b完全执行完以后,线程a才结束阻塞状态.
public class ThreadMethodText {
public static void main(String[] args) {
HelloThread t1=new HelloThread();
t1.setName("线程一");
t1.start();
Thread.currentThread().setName("主线程");
for (int i = 0; i < 100; i++) {
if (i%2==0){
System.out.println(Thread.currentThread().getName()+":"+i);
}
if (i==0){
try {
t1.join();//当i==0时,主线程进入阻塞状态,线程一完全执行完以后主线程结束阻塞
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
4.stop()
已过时,强行结束当前线程的生命周期
5.sleep(Long millitime);
睡眠,让当前线程睡眠指定的millitime毫秒
class HelloThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if (i % 2 == 0) {
try {
sleep(1000);//让当前线程阻塞一秒,一秒后等待下次CPU分配资源才开始执行
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
}
}
6.siAlive():
判断当前线程是否还有生命周期
三.线程的优先级
-
MAX_PRIORITY:10
MIN_PRIOPITY:1
NORM_PRIORITY:5
-
获取和设置当前线程的优先级:
getPriority():获取线程的优先级;
setPriority(int P):设置线程的优先级
说明:优先级高只是概率上高优先级的先执行。
四.线程同步
1.synchronized(){}
(1)大括号中填入对共享数据操作的代码块
(2)小括号中填入任意的对象,在实现Runnable接口中可以考虑填入this,在继承Thread接口中可以考虑使用类来充当对象。
2.synchronized直接修饰方法
3.Lock锁
private ReentrantLock lock=new ReentrantLock;
//使用try{}将要需要同步的代码包裹起来
//然后再try包裹的结构中调用lock.lock方法
//最后添加finall{lock.unlock}方法
四.线程通信
1.方法
wait()方法:一旦执行此方法,当前线程就会进入阻塞状态,并释放同步监视器;
notify()方法:一旦执行此方法,就会唤醒呗wait的一个线程。如果有多个线程,就唤醒优先级高的;
notifyAll()方法:一旦执行此方法,就会唤醒所有呗wait的线程。
2.说明
(1).wait(),notify(),notifyAll()三个方法必须使用在同步代码块或同步方法中;
(2)wait(),notify(),notifyAll()三个方法的调用者必须是同步代码块或同步方法中的同步监视器,否则,会出现I了legalMonitorStateExceptionyic的异常;
(3)wait(),notify(),notifyAll()三个方法是定义在Object类当中的。
五面试题:
sleep()和wait()的异同
1.相同点:
一旦执行方法,都可以是当前的线程进入阻塞状态
2.不同点:
1)两个方法声明的位置不同:Thread类中声明sleep(),Object类中定义wait();
2)调用的要求不同:sleep()可以在任课需要的场景下调用。wait()必须使用在同步代码块和同步方法中;
3)关于是否释放同步监视器:如果两个方法都是用在同步代码块或同步方法中,sleep()不会释放锁,wait()会释放锁。

浙公网安备 33010602011771号