多线程:
进程和线程的区别
区别 | 进程 | 线程 |
根本区别 | 作为资源分配的单位 | 调度和执行的单位 |
开销 | 每个进程都要独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销 | 线程可以看出轻量级的进程,每一类线程共享代码和数据空间,每个线程有独立的运行栈和程序计数器,线程切换的开销小 |
所处环境 | 在操作系统中能同时运行多个任务(程序) | 在同一应用程序中有多个程序流同时执行 |
分配内存 | 系统在运行的时候会为每个内存分配不同的内存区域 | 出CPU外,不会为线程分配内存,(线程所使用的资源是他所属的进程的资源),线程组只能共享资源 |
包含关系 | 没有线程的进程可以看做单线程,如果一个进程有多个线程,则执行过程不是一条线的,而是多条线(线程)共同完成的 | 线程是进程的一部分,所以线程有时候被认为是轻权进程或者轻量级进程 |
线程的创建方法
- 将类声明为thread的子类,该子类重写thread类的run方法,
New 子类().start;
public class Rabbit extends Thread {
@Override
public void run() {
for(int i = 0;i < 100;i++) {
System.out.println("兔子跑了"+i+"步");
}
}
}
public class Test {
public static void main(String[] args) {
Rabbit r = new Rabbit();
r.start();
}
}
- 声明实现runnable接口的类,该类然后实现run方法,
Thread t = new Thread(new 实现类()); t.start();
public class Tortoise implements Runnable {
public void run() {
for(int i = 0;i < 88;i++) {
System.out.println("tortoise run"+i+"step");
}
}
}
public class Test {
public static void main(String[] args) {
Thread t = new Thread(new Tortoise());
t.start();
}
}
- 实现Callable接口,重写call方法
用Executors类的静态方法newFixedThreadPool创建线程池,提交新建的线程获取到线程池中的线程
public class CallbaleDemo {
public static void main(String[] args) throws Exception {
//创建线程
ExecutorService service = Executors.newFixedThreadPool(2);
Future<String> submit = service.submit(new Demo());
//获取值
String s = submit.get();
System.out.println(s);
}
}
class Demo implements Callable<String> {
public String call() {
return "你好";
}
}
//线程匿名内部类:节省了代码直接创建线程
//继承方式
new Thread() {
public void run() {
System.out.println("!!!");
}
}.start();
//接口方式
Runnable r = new Runnable() {
public void run() {
System.out.println("@@@");
}
};
new Thread(r).start();
}
}
****************************************************************************************
线程阻塞join()
public class JoinDemo extends Thread {
public static void main(String[] args) throws InterruptedException {
JoinDemo join = new JoinDemo();
join.start();
for (int i = 0; i < 100; i++) {
System.out.println("main" + i);
if (i == 50) {
join.join();// main阻塞,等待join运行结束,合并线程
}
}
}
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println("join--" + i);
}
}
}
暂停线程Yield
public class YieldDemo extends Thread {
public static void main(String[] args) {
YieldDemo y1 = new YieldDemo();
y1.start();
for(int i = 0;i < 100;i++) {
System.out.println("main"+i);
if(i==50) {
Thread.yield();//静态方法写在main中,main休眠
}
}
}
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println("join--" + i);
}
}
}
任务调度
public class ScheduleDemo {
public static void main(String[] args) {
Timer timer = new Timer();
timer.schedule(new TimerTask() {
public void run() {
System.out.println("hello world");
}
}, new Date(System.currentTimeMillis()+1000),1000);
//1秒后间隔1秒执行timetask()中的run()方法
}
}
线程的方法及优先级
package info;
/*
* 线程中的几个方法
* currentThread() 静态方法,获取到当前线程
* getName() 获取到线程名字
* setName() 设置线程名字
* isAlive() 判断线程是否活着
* setPriority() 设置优先级
*/
public class MyThread implements Runnable {
private boolean flag = true;
private int num = 0;
@Override
public void run() {
while(flag) {
System.out.println(Thread.currentThread().getName()+"--"+num++);
}
}
//线程停止的方法
public void stop() {
this.flag = !this.flag;
}
}
public class InfoDemo {
public static void main(String[] args) throws InterruptedException {
MyThread my = new MyThread();
Thread t = new Thread(my,"shijie");//构造方法对线程命名
t.setName("niaho");
t.start();
System.out.println(t.isAlive());
String name = Thread.currentThread().getName();
System.out.println(name);
Thread.sleep(200);
my.stop();
Thread.sleep(2000);
System.out.println(t.isAlive());
}
}
public class InfoDemo2 {
public static void main(String[] args) throws InterruptedException {
MyThread my1 = new MyThread();
MyThread my2 = new MyThread();
Thread t1 = new Thread(my1,"111");
Thread t2 = new Thread(my2,"222");
t1.setPriority(Thread.MAX_PRIORITY);
t2.setPriority(Thread.MIN_PRIORITY);
t1.start();
t2.start();
Thread.sleep(400);
my1.stop();
my2.stop();
}
}
线程同步
/*
* 多线程共用数据时,通过线程休眠出现安全问题
* 解决方法:java提供同步技术
* 公式:synchronized(任意对象){
* 线程要操作的共享数据
* }
*
* 线程遇到同步时,判断锁,有,获取锁,出同步时,释放锁, 不出去就不释放别人就是进不来
* 判断锁,无,进不去
* 有同步会导致运行速度下降
*/
public class Tickets implements Runnable{
private int tickets = 100;
Object obj = new Object(); //同步随便找的对象
//线程共享数据保证安全,要加入同步代码块
/* public void run() {
while(true) {
synchronized (obj) {
if(tickets > 0) {
System.out.println(Thread.currentThread()+"出售"+tickets--);
}
}
}
}*/
public void run() {
while(true) {
function();
}
}
//同步方法,代码简洁
//同样有同步锁,同步对象为this 本类的对象引用
public synchronized void function() {
if(tickets > 0) {
System.out.println(Thread.currentThread()+"出售"+tickets--);
}
}
}
package threadDemo2;
public class ThreadDemo {
public static void main(String[] args) {
Tickets t = new Tickets();
Thread t0 = new Thread(t);
Thread t1 = new Thread(t);
Thread t2 = new Thread(t);
t0.start();
t1.start();
t2.start();
}
}
线程池;
Runnable接口
- 使用线程池中线程对象的步骤:
- 创建线程池对象
- 创建Runnable接口子类对象
- 提交Runnable接口子类对象
- 关闭线程池
代码演示:
public class ThreadPoolDemo {
public static void main(String[] args) {
//创建线程池对象
ExecutorService service = Executors.newFixedThreadPool(2);//包含2个线程对象
//创建Runnable实例对象
MyRunnable r = new MyRunnable();
//自己创建线程对象的方式
//Thread t = new Thread(r);
//t.start(); ---> 调用MyRunnable中的run()
//从线程池中获取线程对象,然后调用MyRunnable中的run()
service.submit(r);
//再获取个线程对象,调用MyRunnable中的run()
service.submit(r);
service.submit(r);
//注意:submit方法调用结束后,程序并不终止,是因为线程池控制了线程的关闭。将使用完的线程又归还到了线程池中
//关闭线程池
//service.shutdown();
}
}
- Runnable接口实现类
public class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("我要一个教练");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("教练来了: " +Thread.currentThread().getName());
System.out.println("教我游泳,交完后,教练回到了游泳池");
}
}
Callable接口
- Callable接口:与Runnable接口功能相似,用来指定线程的任务。其中的call()方法,用来返回线程任务执行完毕后的结果,call方法可抛出异常。
代码演示:
public class ThreadPoolDemo {
public static void main(String[] args) {
//创建线程池对象
ExecutorService service = Executors.newFixedThreadPool(2);//包含2个线程对象
//创建Callable对象
MyCallable c = new MyCallable();
//从线程池中获取线程对象,然后调用MyRunnable中的run()
service.submit(c);
//再获取个教练
service.submit(c);
service.submit(c);
//注意:submit方法调用结束后,程序并不终止,是因为线程池控制了线程的关闭。将使用完的线程又归还到了线程池中
//关闭线程池
//service.shutdown();
}
}
- Callable接口实现类,call方法可抛出异常、返回线程任务执行完毕后的结果
public class MyCallable implements Callable {
@Override
public Object call() throws Exception {
System.out.println("我要一个教练:call");
Thread.sleep(2000);
System.out.println("教练来了: " +Thread.currentThread().getName());
System.out.println("教我游泳,交完后,教练回到了游泳池");
return null;
}
}