多线程
并行与并发
并行:逻辑上同时发生,指在某一个时间内同时运行多个程序。
并发:物理上同时发生,指在某一个时间点同时运行多个程序。
java可以通过两种方式实现多线程程序:
一般来说,被线程执行的代码肯定是比较耗时的。
多线程的方式一:
继承Thread类
步骤:
------|A / 自定义类MyThread继承Thread类
------|B / MyThread类里面重写run()方法
**不是类中的所有代码都需要被多线程执行,这个时候,为了区分哪些需要多线程执行,Java提供了Thread类中的run()用来包含那些被多线程执行的代码。
------|C / 创建对象
------|D / 启动线程 start()方法
**Start():首先启动了线程,然后在由JVM调用run()运行方法
范例:
package cn.itcast_01;
/*
* MyThread
* 需要重写run()方法
*
*/
public class MyThread extends Thread {
@Override
public void run() {
for(int x =0;x<2000;x++){
System.out.println(x);
}
}
}
package cn.itcast_01;
/*
* 测试类
*
*/
public class MyThreadTest_01 {
public static void main(String[] args) {
//创建线程对象
/* MyThread my = new MyThread();
my.start();
//IllegalThreadStateException 非法的的线程状态异常
//my.start();同一个线程不能同时调用两次
*/
//创建两个线程对象,才能调用两个线程,不能一个线程调用多次。
MyThread my1 = new MyThread();
MyThread my2 = new MyThread();
my1.start();
my2.start();
}
}
public final String getName() :获取线程的名称
public final void setName(String name) :设置线程名称
范例:
package cn.itcast_02;
/*
* MyThread
*
*/
public class MyThread extends Thread {
@Override
public void run() {
for(int x=0; x<1000;x++){
System.out.println(getName()+":"+x); //加入获取线程名称的方法
}
}
}
package cn.itcast_02;
/*
* 测试类
*/
public class MyThreadDemo {
public static void main(String[] args) {
//创建线程对象
MyThread my1 = new MyThread();
MyThread my2 = new MyThread();
MyThread my3 = new MyThread();
//设置线程名称
my1.setName("第一线程:");
my2.setName("第二线程:");
my1.start();
my2.start();
}
}
线程调度:
线程的两种调度模型:
A / 分时调度模型 所有线程轮流使用CPU的使用权,平均分配每个线程占用CPU的时间片
B / 抢占式调度模型 优先让优先级高的线程使用CPU,如果线程的优先级相同,那么会随机选择一个,优先级高的线程获取的CPU时间片相对多些。
用到的方法:
public final void setPriority( int newPriority)更改线程优先级
public final int getPriority() 返回线程对象的优先级
线程控制:
线程休眠:
public static void sleep(long millis)
范例:
package cn.itcast_03;
public class ThreadSleep extends Thread {
@Override
public void run() {
for(int x =0; x<500;x++){
System.out.println(getName()+":"+x);
//睡眠 //会抛出异常
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
package cn.itcast_03;
/*
* 测试方法
*
*/
public class ThreadSleepDemo {
public static void main(String[] args) {
//创建线程对象
ThreadSleep ts1 = new ThreadSleep();
ThreadSleep ts2 = new ThreadSleep();
ThreadSleep ts3 = new ThreadSleep();
ts1.setName("唐僧");
ts2.setName("孙悟空");
ts3.setName("猪八戒");
ts1.start();
ts2.start();
ts3.start();
}
}
线程加入: // 等待该线程终止后其它线程才能继续。
public final void join()
package cn.itcast_03;
/*
* ThreadJoin
*/
public class ThreadJoin extends Thread {
public void run() {
for(int x =0; x<500;x++){
System.out.println(getName()+":"+x);
}
}
}
package cn.itcast_03;
/*
* ThreadJoin测试
*/
public class ThreadJoinDemo {
public static void main(String[] args) {
//创建线程对象
ThreadJoin tj1 = new ThreadJoin();
ThreadJoin tj2 = new ThreadJoin();
ThreadJoin tj3 = new ThreadJoin();
tj1.start(); //这个线程加入了jion,必须它走完了后面的线程才能继续
try {
tj1.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
tj2.start();
tj3.start();
}
}
线程礼让: //暂停当前正在执行的对象,并执行其它线程
public static void yield()
package cn.itcast_03;
/*
* ThreadYield
*
*/
public class ThreadYield extends Thread {
public void run() {
for(int x =0; x<500;x++){
System.out.println(getName()+":"+x);
Thread.yield(); //加入线程礼让
}
}
}
package cn.itcast_03;
/*
* ThreadYield测试
*
*/
public class ThreadYieldDemo {
public static void main(String[] args) {
//创建线程对象
ThreadYield ty1 = new ThreadYield();
ThreadYield ty2 = new ThreadYield();
ThreadYield ty3 = new ThreadYield();
ty1.start();
ty2.start();
ty3.start();
}
}
后台线程(守护线程):当正在运行的线程都是守护线程是,JAVA虚拟机退出。该方法必须在启动线程前调用。
public final void setDaemon(boolean on)
package cn.itcast_03;
/*
* ThreadDaemon后台线程
*
*/
public class ThreadDaemon extends Thread {
public void run() {
for(int x =0; x<500;x++){
System.out.println(getName()+":"+x);
}
}
}
package cn.itcast_03;
/*
* ThreadDaemon
* 下列程序中,当td3运行完了,td1和td2就会终止
*/
public class ThreadDaemonDemo {
public static void main(String[] args) {
ThreadDaemon td1 = new ThreadDaemon();
ThreadDaemon td2 = new ThreadDaemon();
td1.setDaemon(true);
td2.setDaemon(true);
td1.start();
td2.start();
Thread.currentThread().setName("td3");
for(int x = 0; x<100;x++){
System.out.println(x);
}
}
}
中断线程:
public final void stop() //停止线程,过时了,但是还可以使用。
public void interrupt() 中断线程,
多线程的实现方式二:
Runnable 接口
创建线程的另一种方法是声明实现 Runnable
接口的类。该类然后实现 run
方法
思路(步骤):
A / 自定义类MyRunnable 实现Runnable接口
B / 重写run()方法
C / 创建MyRunnable类的对象
D / 创建Thread类的对象,并把C步骤的对象作为参数传递
范例:
package cn.itcast_04;
public class MyRunnable implements Runnable {
@Override
public void run() {
for(int x = 0;x<500;x++){
//由于实现接口的方式不能直接使用Thread类的方法,可以通过通过获取当前正在执行的线程来调用getName方法
System.out.println(Thread.currentThread().getName()+":"+x);
}
}
}
package cn.itcast_04;
/*
* 思路(步骤):
A / 自定义类MyRunnable 实现Runnable接口
B / 重写run()方法
C / 创建MyRunnable类的对象
D / 创建Thread类的对象,并把C步骤的对象作为参数传递
*/
public class RunnableDemo {
public static void main(String[] args) {
//创建MyRunnable类的对象
MyRunnable mr = new MyRunnable();
// 创建Thread类的对象,并把C步骤的对象作为参数传递
Thread th1 = new Thread(mr);
Thread th2 = new Thread(mr);
th1.start();
th2.start();
}
}
两种方式的比较和区别:
方式二解决了单继承的局限性。