多线程
线程和进程
进程:就是执行中的程序
进程是操作系统的资源分配单位,创建并执行一个进程的系统开销是比较大的。
多线程是指在单个进程下运行不同的线程,执行不同的任务。
同一进程下的线程共享该进程的内存空间和资源
实现多线程(继承thread类)
通过继承thread类来实现多线程
thread类存放在java.lang类库里。java.lang包中提供常用的类,接口,一般异常,系统等编程语言的核心内容
在thread类中定义了run方法。想要实现多线程,必须覆写thread类的run方法。
class 类名 extends Thread
{
属性
方法
修饰符 run()
{
程序代码;//激活的线程将从run方法开始执行
}
}
通过runnable接口实现多线程
如果一个类已经继承了其他类,又要使用多线程,这个时候,就要使用runnable接口
class 类名称 implement Runnable
{
//属性
//方法
public void run()
{
//
}
}
两种多线程实现机制比较
在本质上,thread类是implement接口的一个子类
class testthread extends Thread
//class testthread implements Runnable
{
private int tickets=5;
public void run()
{
while(tickets>0)
{
System.out.println(Thread.currentThread().getName()+"出售票"+tickets);
tickets--;
}
}
}
public class demo {
public static void main(String []args)
{
testthread t=new testthread();
//方案一,继承接口或者线程类
/*new Thread(t).start();
new Thread(t).start();
new Thread(t).start();
new Thread(t).start();*/
//方案二,继承线程类
/*new testthread().start();
new testthread().start();
new testthread().start();
new testthread().start();*/
//方案三,继承线程类
/*t.start();
t.start();
t.start();
t.start();*/
}
方案一:启动四个进程,并实现资源共享的目的
方案二:启动四个线程,分别各自操作
方案三:一个线程只能启动一次
使用runnable接口有明显优势
1.避免单继承带来的局限
2.可以使多个线程共享相同的资源,达到资源共享的目的
线程的状态(创建,就绪,执行,阻塞,终止)
线程的五个状态:创建,就绪,运行,阻塞,终止
1.new:创建态,尚未启动的线程处于创建状态
2.runnable:运行态,在虚拟机中执行的线程处于这个状态
3.blocked:阻塞态,受阻塞并等待某个监视器锁的线程处于此线程
4.waiting:无限等待
5.timed_waiting:显示等待
6.terminated:终止态
class testthread extends Thread
{
public void run()
{
System.out.println("处于运行状态");
Scanner scan=new Scanner(System.in);
System.out.println("处于阻塞状态");
System.out.println("请输入:");
scan.next();//next方法扫描scan输入的字符串
scan.close();
System.out.println("结束阻塞状态,处于就绪状态");
try {
Thread.sleep(1000);
}
catch(InterruptedException e)
{
e.printStackTrace();
}
System.out.println("处于死亡状态");
}
}
public class demo {
public static void main(String []args)
{
testthread t=new testthread();
System.out.println("处于创建状态");
t.start();
System.out.println("处于就绪状态");
}
}
线程操作的一些方法
取得和设置线程的名称
class testthread extends Thread
{
public void run()
{
Thread t=Thread.currentThread();
System.out.println("执行这条语句的线程名称:"+t.getName());
}
}
public class demo {
public void printname()
{
}
public static void main(String []args)
{
Thread t=new Thread(new testthread());
t.setName("我的线程");
t.start();
}
}
start()和run()方法的不同
1.start()方法的作用是启动一个新的线程,这时无需等到run方法体的代码运行完毕,而是直接继续执行start其后的代码。
2.run方法和普通的成员方法一样,它并不会开启新的线程
判断线程是否启动 isAlive()
class testthread extends Thread
{
public void run()
{
Thread t=Thread.currentThread();
System.out.println("执行这条语句的线程名称:"+t.getName());
}
}
public class demo {
public void printname()
{
}
public static void main(String []args)
{
Thread t=new Thread(new testthread());
t.setName("我的线程");
System.out.println("线程是否存活:"+t.isAlive());
t.start();
System.out.println("线程是否存活:"+t.isAlive());
}
}
守护进程与setDaemon方法
JVM中线程分为,用户线程(也称,前台进程,一般进程)和守护进程(后台进程)。
例如:垃圾回收线程就是守护进程。
守护进程就是守护其他进程的进程
默认创建进程都属于普通进程
private boolean daemon=false
只有调用setdaemon(true)之后才能转为守护进程
class testthread extends Thread
{
public void run()
{
for(int i=0;true;i++)
{
System.out.println("执行这条语句的线程名称:"+Thread.currentThread().getName());
}
}
}
public class demo {
public void printname()
{
}
public static void main(String []args)
{
Thread t=new Thread(new testthread());
t.setName("我的线程");
System.out.println("线程是否存活:"+t.isAlive());
t.setDaemon(true);// 必须在start方法之前
t.start();
System.out.println("线程是否存活:"+t.isAlive());
}
在此例之中,虽然创建的线程是无线循环的,但是因为此线程是守护线程,在main方法结束后,守护线程也就随之结束
线程的联合join()
class testthread extends Thread
{
public void run()
{
for(int i=0;i<5;i++)
{
try {
Thread.sleep(1000);
}
catch(Exception e)
{
e.printStackTrace();
}
System.out.println("执行这条语句的线程名称:"+Thread.currentThread().getName());
}
}
}
public class demo {
public static void main(String []args)
{
Thread t=new Thread(new testthread());
t.start();
int i=0;
for(int x=0;x<5;x++)
{
if(i==3)
{
try
{
t.join();
}
catch(Exception e)
{
e.printStackTrace();
}
}
System.out.println("main thread"+i);
i++;
}
}
}
线程A在占用CPU期间,如果联合了线程B,A线程立即挂起,知道线程B执行完毕
线程的中断
Thread.interrupt()
Thread.isInterrupted()
Thread.interrupted()
中断对于正在运行的线程不起作用,只有对阻塞的线程有效。
多线程的同步
保证代码段的原子性(要不不被执行,要不执行了就不会中途打断)
class testthread extends Thread
{
private int tickets=5;
public void run()
{
while(true)
{
synchronized(this)
{
if(tickets<=0)
break;
try
{
Thread.sleep(100);
}
catch(Exception e)
{
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"出售票"+tickets);
tickets--;
}
}
}
}
public class demo {
public static void main(String []args)
{
testthread t=new testthread();
//方案一,继承接口或者线程类
new Thread(t).start();
new Thread(t).start();
new Thread(t).start();
new Thread(t).start();
}
}
同步方法
除了同步代码块,也可以同步方法,在方法前面加上synchronized关键字就行
死锁
public class demo {
static String knife="餐刀",fork="叉子";
static class A extends Thread
{
public void run()
{
//while(true)
//{
synchronized(knife)
{
System.out.println("A=已经拿到餐刀,在等待叉子。。。");
try
{
Thread.sleep(1000);
}
catch(Exception e)
{
e.printStackTrace();
}
}
synchronized(fork)
{
/*try
{
Thread.sleep(1000);
}
catch(Exception e)
{
e.printStackTrace();
}*/
System.out.println("A=已经拿到叉子,在等待餐刀。。。");
}
//}
}
}
static class B extends Thread
{
public void run()
{
//while(true)
//{
synchronized(fork)
{
System.out.println("B=已经拿到叉子,在等待餐刀。。。");
try
{
Thread.sleep(100);
}
catch(Exception e)
{
e.printStackTrace();
}
}
synchronized(knife)
{
/*try
{
Thread.sleep(1000);
}
catch(Exception e)
{
e.printStackTrace();
}*/
System.out.println("B=已经拿到餐刀,在等待叉子。。。");
}
//}
}
}
static class deadlock extends Thread
{
public deadlock()
{
this.setDaemon(true);
}
public void run()
{
System.out.println("守护进程在运行。。。");
try
{
Thread.sleep(100);
}
catch(InterruptedException e)
{
}
}
}
public static void main(String []args)
{
new A().start();
new B().start();
new deadlock().start();
}
}