【多线程】线程状态,线程组,线程锁,线程中断
进程拥有一个完整的虚拟地址空间,不依赖于线程而独立存在;
线程是进程的一部分,没有自己的地址空间,与进程内的其他线程一起共享分配给该进程的所有资源。一个线程可以创建和撤消另一个线程,线程有时被称为轻量级进程(Lightweight Process,LWP)程序执行流的最小单元,一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成。
线程有创建,可运行,运行中,阻塞,死亡五种状态。
1.创建状态
使用new运算符创建一个线程后,该线程仅仅是一个空对象,系统没有分配资源,称该线程处于创建状态(new thread)
2.可运行状态
使用start()方法启动一个线程后,系统为该线程分配了除CPU外的所需资源,使该线程处于可运行状态(Runnable)
3.运行中状态
Java运行系统通过调度选中一个Runnable的线程,使其占有CPU并转为运行中状态(Running).此时,系统真正执行线程的run()方法.
4.阻塞状态
一个正在运行的线程因某种原因不能继续运行时,进入阻塞状态(Blocked)
5.死亡状态
线程结束后是死亡状态(Dead)
线程可以通过三种方式创建 实现Runnable接口,实现Callable接口和继承Thread类(Thread类也是实现了Runnable接口)
第一种:通过实现Runnable接口创建线程
public class RunnableDemo2 implements Runnable {
private Thread t;
private String ThreadName;
public RunnableDemo2(String ThreadName){
this.ThreadName=ThreadName;
}
@Override
public void run() {
for(int i=0;i<4;i++){
try {
System.out.println(ThreadName+" 拿到"+i);
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
Thread t1=new Thread(new RunnableDemo2("线程1 "));
Thread t2=new Thread(new RunnableDemo2("线程2 "));
t1.start();
t2.start();
}
}
第二种:通过继承Thread类创建线程
public class ThreadDemo1 extends Thread{
private String ThreadName;
private Thread t;
public ThreadDemo1(String ThreadName){
this.ThreadName=ThreadName;
}
@Override
public void run() {
for(int i=0;i<9;i++){
System.out.println(ThreadName+"执行");
try {
Thread.sleep((int)(Math.random()*30));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
Thread t1=new Thread(new ThreadDemo1("线程A"));
Thread t2=new Thread(new ThreadDemo1("线程B"));
t1.start();
t2.start();
}
}
第三种
//通过实现Callable接口来创建线程
public class CallableThreadTest implements Callable<Integer>{
public static void main(String[] args) {
CallableThreadTest ctt=new CallableThreadTest();
FutureTask<Integer> ft = new FutureTask<Integer>((Callable<Integer>) ctt);
for(int i=0;i<30;i++){
System.out.println(Thread.currentThread().getName()+"的循环变量i的值");
//开启线程,传入FutureTask对象
new Thread(ft,"有返回值的线程").start();
}
//执行完返回子线程的值
try {
System.out.println("子线程的返回值:"+ft.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
@Override
public Integer call() throws Exception {
int i=0;
for(;i<50;i++){
System.out.println(Thread.currentThread().getName()+""+i);
}
return i;
}
}
线程组:线程组把多个线程集成为一个对象,通过线程组可以同时对其中的多个线程进行操作
线程默认情况下属于main线程组
创建线程组:
对线程组进行操作的方法如下所示:
resume(); //使被挂起的当前组内的线程恢复到可运行状态
etDaemon (boolean daemon); //指定一个线程为当前线程组的监护线程
setMaxPriority(int pri); //设置当前线程组允许的最大优先级
stop(); //终止当前线程组中所有线程
suspend(); //挂起当前线程组中所有线程
toStrinng(); //将当前线程组转换为String类的对象
public static void main(String[] args) {
ThreadGroup group1=new ThreadGroup("group1"); //创建线程组group1
ThreadGroup group2=new ThreadGroup(group1,"group2"); //创建线程组group2,并将group2加入线程组group1
ThreadGroup group3=new ThreadGroup("group3");
Thread thread1=new Thread(group2,new Mythread("线程 1"));
Thread thread2=new Thread(group2,new Mythread("线程 2"));
Thread thread3=new Thread(group3,new Mythread("线程 3"));
Thread thread4=new Thread(group3,new Mythread("线程 4"));
thread1.start();
thread2.start();
thread3.start();
thread4.start();
while (Thread.currentThread().getThreadGroup().activeCount() != 1) {
Thread.yield();
}
System.err.println("over");
}
}
[线程同步]
银行存取钱时,不能对同一账户同时进行存和取的操作,只能一个操作进行完成才能进行另一个操作。
//储蓄账户
class BlankSaving {
private static int money=10000;
public void add(int i){
money=money+i;System.out.println("Husband 向银行存入了 [¥"+i+"]");
}
public void get(int i){
money=money-i;System.out.println("Wife 向银行取走了 [¥"+i+"]");
if(money<0)System.out.println("余额不足!");
}
public int showMoney(){
return money;
}
}
class Operater implements Runnable{
String name;
BlankSaving bs;
public Operater(BlankSaving b,String s){
name=s;
bs=b;
}
public synchronized static void oper(String name,BlankSaving bs){
if(name.equals("husband")){
try{for(int i=0;i<10;i++){
Thread.currentThread().sleep((int)(Math.random()*300));
bs.add(1000);}
}catch(InterruptedException e){}
}
else{
try{for(int i=0;i<10;i++){
Thread.currentThread().sleep((int)(Math.random()*300));
bs.get(1000);}
}catch(InterruptedException e){}}
}
public void run(){
oper(name,bs);}
}
public class BankTest {
public static void main(String[] args)throws InterruptedException{
BlankSaving bs=new BlankSaving();
Operater o1=new Operater(bs,"husband");
Operater o2=new Operater(bs,"wife");
Thread t1=new Thread(o1);
Thread t2=new Thread(o2);
t1.start();
t2.start();
Thread.currentThread().sleep(500);
}
}
未加synchronized之前执行结果
加了synchronized之后
【线程挂起和唤醒】
class MyThread_1 extends Thread{
Object lockName;
public MyThread_1(Object lockName){
this.lockName=lockName;
}
public void run(){
try{
synchronized(lockName){
System.out.println("线程1:“我运行了”");
lockName.wait(); //将线程对象挂起
System.out.println("线程1 :“我被唤醒啦。。。(由阻塞变成可运行状态)”");
}}catch(InterruptedException e){}
}}
class MyThread_2 extends Thread{
Object lockName;
public MyThread_2(Object lockName){
this.lockName=lockName;
}
public void run(){
synchronized(lockName){
System.out.println("线程2:“我运行了”");
lockName.notify(); //唤醒线程1
}
}
}
public class MyThread{
public static void main(String[] args){
int[] in=new int[0];//java中创建一个0长度的数组来充当锁更加高效
//notice
MyThread_1 t1=new MyThread_1(in);
MyThread_2 t2=new MyThread_2(in);
t1.start();
t2.start();
}
}
执行结果;
线程中断 Interrupt
注意:不是停止线程,而是在线程等待(死锁)的时候抛出一个InterruptedException异常,如果我们要停止该线程直接捕获该异常进行return即可
上一篇: 手机平台应用开发实验报告1
下一篇: Java 锁-Lock接口简介