Java 多线程篇(1)
在java开发过程中通常会遇到需要多条路径来执行某个任务,比如一个后台程序连接多个客户端,不可能让一个客户端完成它所有的工作之后才能让其他客户端连接
因此就需要使用的多线程技术
一个java程序至少包含俩个线程,1.主线程 2. 垃圾回收线程
本身的函数是一条主线程
多线程是为了同时运行多部分的代码,但CPU只有一个,因此是在多个线程中随机切换,所以一旦线程过多会影响效率
java中使用多线程的两种方式
一、通过继承Thread类
首先通过继承Thread类并重写Thread中的run方法,run方法中的内容是线程的执行任务
Thread 类中有start()方法,用来开启线程执行run方法中的内容
stop()方法则是终止线程的执行
public class MyDemo extends Thread {
public void run() {
for (int i = 0; i < 50; i++)
System.out.println("---" + i);
}
public static void main(String[] args) {
MyDemo mydemo = new MyDemo();
MyDemo mydemo2 = new MyDemo();
mydemo.start();
mydemo2.start();
}
}
运行结果:
—0 —0 —1 —2 —3 —4 —1 —5 —2 —6 —7 —8 —9 —10 —11 —12
—13 —14 —15 —16 —17 —18 —19 —20 —21
两个线程将会执行run 方法中的代码
并且两个线程的运行是随机的,cpu在两个线程之间随机切换
二、实现Runnable接口
class Demo implements Runnable{
public void run(){
show();
}
Demo d = new Demo();//先创建继承了接口的类的对象,
Thread t1 = new Thread (d);//需要将对象传入线程中
Thread t2 = new Thread (d);
t1.start();
t2.start();
}
Runnable中只有一个方法就是run() <仅仅是为了将线程任务进行对象的封装>
原理:
class Thread implements Runnable{
private Runnable r;
Thread(){}
Thread(Runnable r){
this.r = r;
}
public void run(){
if(r!=null){
r.run();
}
}
public void start(){
run();
}
}
Thread 类中有多个构造方法,其中有一个需要传入对象 还有一个不需要任何参数
所以如果有对象传入将会把该对象中的run()方法也传入,从而利用线程对象调用的start()方法能完成 传入的对象 的任务(run方法)
使用接口的好处:
- 将线程的任务从子类中分离进行了单独封装
避免单继承的局限性
利用实现Runnable接口完成多线程更常用
线程有几个常用的方法
- void run();线程的主要执行代码
- void start();使该线程开始启动,Java 虚拟机负责调用该线程的 run()方法。
//多次启动一个线程是非法的。
- void stop();中断线程的运行
- void sleep(long millis):Thread类静态方法,线程进入阻塞状态,在指定时间(单位为毫秒)到达之后进入
//就绪状态,而非立即进入执行状态。
- void wait();使当前线程暂停执行并释放对象锁标示,让其他线程可以进入synchronized数据块
- void notify();唤醒在此对象监视器上等待的单个线程,如果等待线程有多个,则会选择唤醒其中一个线程
进入就绪状态,选择是任意性的
- void notifyAll() 唤醒此对象上的所有等待的线程使他们进入就绪状态
- void yield():静态方法,当前线程放弃占用CPU资源,回到就绪状态,使其他优先级不低于此线程
的线程有机会被执行。
- void setPriority(int newPriority):设置当前线程的优先级。
- int getPriority():获得当前线程的优先级。
-void join();调用线程被阻塞,知道join方法加入的线程执行完成时候再继续执行
wait notify() notifyAll() 这三个方法都是属于Object类的方法,只能在同步控制方法或者同步控制块里面使用
sleep()和wait()的区别
- 首先一个最明显的区别是 wait是Object类的方法,而sleep()是Thread类的静态方法,谁调用了该方法谁去休眠
- 比较重要的一点是sleep没有释放出锁,而wait释放了锁,一般wait不会加时间限制,需要用notify来唤醒
- wait只能在同步控制方法或者同步控制块里面使用,而sleep可以在任何地方使用
- sleep()使用时需要捕获异常 利用
try { Thread.sleep(100);//睡眠100毫秒 }
catch(InterruptedException e) { }
join()方法
//假设此线程为1线程
package yd;
public class Main extends Thread {
/**
* 主函数
*/
public static void main(String[] args) {
new Main().start();
}
public void run() {
JoinThread jt = new JoinThread();
jt.start();
try {
jt.join();// join线程加入,主线程阻塞
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("main线程执行");
}
}
class JoinThread extends Thread {
public void run() {
System.out.println("join线程执行");
try {
sleep(1000);//加上睡眠,便于观察
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
运行结果:
join线程执行 (过了一秒之后)(这一秒是sleep中的设置的)
mian线程执行
守护线程 Daemon
代码实例
public class Main {
/**
* 主函数
*/
public static void main(String[] args) {
JoinThread jt = new JoinThread();
jt.start();
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
jt.flag = false;
}
}
class JoinThread extends Thread {
static boolean flag = true;
public void run() {
int num = 0;
DaemonThread dt = new DaemonThread();
dt.setName("守护线程---");
dt.setDaemon(true);
dt.start();
while (flag) {
try {
sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + num++);
}
System.out.println(Thread.currentThread().getName() + "结束");
}
}
class DaemonThread extends Thread {
public void run() {
int num = 0;
while (true) {
try {
sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + num++);
}
}
}
结果:
守护线程---0 Thread-00
守护线程---1 Thread-01
守护线程---2 Thread-02
守护线程---3 Thread-03
守护线程---4 Thread-04
守护线程---5 Thread-05
守护线程---6 Thread-06
Thread-07 守护线程---7
守护线程---8 Thread-08
Thread-09 守护线程---9(守护线程随着Thread的结束而结束)
如果将dt.setDaemon(true);注释掉之后
当Thread运行到9 的时候结束
但是 dt线程会继续运行