Java-多线程

一、进程和线程

多进程:在操作系统中可以同时运行多个运用程序。
多线程:在同一个运用程序中可以有多个执行的路径。
进程和线程的区别:

  1. 进程是系统资源调度和分配的基本单位,线程是CPU调度和分配的基本单位。
  2. 一个线程只能属于一个进程,一个进程可以拥有多个线程,但是至少有一个线程(称为主线程,Android系统中也称为UI线程)。
  3. 进程之间不能共享内存,线程之间可以共享内存,但是在线程之间通信需要注意数据同步的问题。

二、线程

Thread类

1、创建多线程

创建新执行线程有两种方法。一种方法是将类声明为 Thread 的子类。该子类应重写 Thread 类的 run 方法。接下来可以分配并启动该子类的实例。

class MyThread extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println("MyThread1:" + i);
        }
    }
}
MyThread thread = new MyThread();
thread.start();

另一个方法是:3. 声明一个实现Runnable接口的子类,重写run()方法。使用的时候,声明一个Thread类的实例,把Runnable的子类对象传入就可以了。

class MyThread2 implements Runnable{

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println("MyThread2:"+i);
        }
    }
}
MyThread2 thread2 = new MyThread2();
new Thread(thread2).start();

在创建线程的时候可以传入一个指定线程名称的参数,如果没有指定线程名,则会默认一个线程名称为”Thread-0”(0表示子线程的数量,从0开始计数)。

问题:继承Thread类和实现Runnable接口的区别?
(1)实现Runnable接口可以解决单继承的局限问题;
(2)方便解决多个线程操作同一个数据的问题。

2、多线程的优先级

每个线程都有一个优先级,高优先级线程的执行优先于低优先级线程,所以对执行结果会有一定的影响。

public final static int MIN_PRIORITY = 1;//最低优先级
public final static int NORM_PRIORITY = 5;//正常优先级
public final static int MAX_PRIORITY = 10;//最大优先级
3、常用方法
public static Thread currentThread();//返回对当前正在执行的线程对象的引用。

public long getId();//返回该线程的标识符。线程 ID 是一个正的 long 数,在创建该线程时生成。线程 ID 是唯一的,并终生不变。

public final void setName(String name);//改变线程名称,使之与参数 name 相同
public final String getName();//返回该线程的名称

public final void setPriority(int newPriority);//更改线程的优先级。
public final int getPriority();//返回线程的优先级。


public final ThreadGroup getThreadGroup();//返回该线程所属的线程组。 如果该线程已经终止(停止运行),该方法则返回 null。 

public final void join();//等待该线程终止。
public final void join(long millis);//等待该线程终止的时间最长为 millis 毫秒。
public final void join(long millis,int nanos);//等待该线程终止的时间最长为 millis 毫秒 + nanos 纳秒。 
join:插队。如果A线程要礼让B线程,需要在A线程中去调用B线程的join方法,才会起到插队的效果(主线程和子线程同时运行,满足一定条件后,让子线程先运行)。

public static void sleep(long millis);
public static void sleep(long millis,int nanos);//在指定的时间内让当前正在执行的线程休眠(暂停执行),该线程处于阻塞状态。

public static void yield();//暂停当前正在执行的线程对象,并执行其他线程。
Yield()方法是停止当前线程,让同等优先权的线程运行,如果没有同等优先权的线程,那么Yield()方法将不会起作用。 

public final void setDaemon(boolean on);//将该线程标记为守护线程或用户线程。当正在运行的线程都是守护线程时(没有了被守护者),Java 虚拟机退出。 该方法必须在启动线程前调用。

所谓守护线程,是指在程序运行的时候在后台提供一种通用服务的线程,比如垃圾回收线程就是一个很称职的守护者。

public final boolean isDaemon();//测试该线程是否为守护线程

public String toString();//返回该线程的字符串表示形式,包括线程名称、优先级和线程组。

public void start();//使该线程开始执行;Java 虚拟机调用该线程的 run 方法。 
//结果是两个线程并发地运行;当前线程(从调用返回给 start 方法)和另一个线程(执行其 run 方法)。

public void run();//如果该线程是使用独立的 Runnable 运行对象构造的,则调用该 Runnable 对象的 run 方法;否则,该方法不执行任何操作并返回。

public final void stop();//(已过时)强迫线程停止执行。

public void interrupt();//中断线程

interrupt()中断线程。需要注意的是,InterruptedException是线程自己从内部抛出的,并不是interrupt()方法抛出的。
对某一线程调用interrupt()时,如果该线程正在执行普通的代码,那么该线程根本就不会抛出InterruptedException。
但是,一旦该线程进入到wait()/sleep()/join()后,就会立刻抛出InterruptedException

public static boolean interrupted();//测试当前线程是否已经中断
public boolean isInterrupted();//测试线程是否已经中断

public final void wait(long timeout)
public final void wait(long timeout,int nanos)
public final void wait();//在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,导致当前线程等待。

public final void notify();//唤醒在此对象监视器上等待的单个线程。
public final void notifyAll();//唤醒在此对象监视器上等待的所有线程。线程通过调用其中一个 wait 方法,在对象的监视器上等待

例:设置线程的优先级,高优先级的线程会优先执行。

public class PriorityTest {

    public static void main(String[] args) {
        PriorityThread t1 = new PriorityThread("张三");
        PriorityThread t2 = new PriorityThread("李四");
        t1.start();
        t2.start();
        System.out.println(t1.getPriority()+":"+t2.getPriority());
        t1.setPriority(Thread.MAX_PRIORITY);
        t2.setPriority(Thread.MIN_PRIORITY);
        System.out.println(t1.getPriority()+":"+t2.getPriority());
    }

}
class PriorityThread extends Thread {
    private String threadName;
    public PriorityThread(String threadName){
        super(threadName);
    }
    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
    System.out.println(Thread.currentThread().getName()+":" + i);
    try {
        Thread.sleep(1000);
        } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
        }
    }
}
    public String getThreadName() {
        return threadName;
    }
    public void setThreadName(String threadName) {
        this.threadName = threadName;
    }
}

输出结果:

张三:0
李四:0
设置前:t1=5:t2=5
设置后:t1=10:t2=1
张三:1
李四:1
张三:2
李四:2
李四:3
张三:3
张三:4
李四:4

结果可以看出线程”张三”比线程”李四”更优先执行
例:Sleep()休眠一段时间

public class SleepTest {

    public static void main(String[] args) {
        TimeThread t1 = new TimeThread();
        TimeThread t2 = new TimeThread();
        t1.start();
        t2.start();
    }

}
class TimeThread extends Thread{
    @Override
    public void run() {
        while(true){
            System.out.println(Thread.currentThread().getName()+":"+new Date());
            try {
                sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

    }
}

输出结果:

Thread-0:Wed Mar 16 22:08:33 CST 2016
Thread-1:Wed Mar 16 22:08:33 CST 2016
Thread-0:Wed Mar 16 22:08:34 CST 2016
Thread-1:Wed Mar 16 22:08:34 CST 2016
Thread-0:Wed Mar 16 22:08:35 CST 2016
Thread-1:Wed Mar 16 22:08:35 CST 2016
Thread-0:Wed Mar 16 22:08:36 CST 2016
Thread-1:Wed Mar 16 22:08:36 CST 2016

每个1s执行一次线程
例:Join,主线程礼让子线程

public class JoinTest {

    public static void main(String[] args) {
        JoinThread t1 = new JoinThread();
        t1.start();
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName() + ":" + i);
            if (i == 2) {
                try {
                    t1.join();//t1子线程优先执行完后,再执行主线程
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    }
}

class JoinThread extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(getName() + ":" + i);
        }
    }
}

输出结果:

main:0
main:1
main:2
Thread-0:0
Thread-0:1
Thread-0:2
Thread-0:3
Thread-0:4
Thread-0:5
Thread-0:6
Thread-0:7
Thread-0:8
Thread-0:9
main:3
main:4
main:5
main:6
main:7
main:8
main:9

当主线程中i的值为2时,子线程优先执行完,然后再继续执行主线程

例:interrupt中断线程,线程进入到wait()/sleep()/join()后,会抛出interruptexception异常。

public class InterruptTest2 {

    public static void main(String[] args) {
        InterruptThread2 t = new InterruptThread2();
        t.start();
        t.interrupt();
    }
}

class InterruptThread2 extends Thread {
    @Override
    public void run() {
        System.out.println("开始");

        System.out.println("ok");
        try {
            sleep(1000);
        } catch (InterruptedException e) {
            System.out.println("出现异常");
            e.printStackTrace();
        }

        System.out.println("结束");
    }
}

输出结果:

开始
ok
出现异常
结束
java.lang.InterruptedException: sleep interrupted
    at java.lang.Thread.sleep(Native Method)
    at com.thread.InterruptThread2.run(InterruptTest2.java:19)

如果需要中断线程,一般设置一个标志位,在要中断的线程中改变这个标志位。

public class InterruptTest {

    public static void main(String[] args) {
        InterruptThread t = new InterruptThread();
        t.start();
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        t.setStop(false);//
//      t.interrupt();
    }
}

class InterruptThread extends Thread {
    private boolean flag = true;
    @Override
    public void run() {
        while (flag) {
            System.out.println("ok");
        }
    }

    public void setStop(boolean flag) {
        this.flag = flag;
    }
}

关于线程的几个常用方法的使用,参考链接:
http://zheng12tian.iteye.com/blog/1233638

4、线程的生命周期

线程生命周期

a) 新建状态
i. 在程序中用构造方法创建了一个线程对象后,新的线程对象便处于新建状态,此时,它已经有了相应的内存空间和其它资源,但还处于不可运行状态。新建一个线程对象可采用线程构造方法来实现。
ii. 例如:Thread thread=new Thread();
b) 就绪状态
i. 新建线程对象后,调用该线程的start()方法就可以启动线程。当线程启动时,线程进入就绪状态。此时,线程将进入线程队列排队,等待CPU调用,这表明它已经具备了运行条件。
c) 运行状态
i. 当就绪状态的线程被调用并获得处理器资源时,线程就进入了运行状态。此时,自动调用该线程对象的run()方法。run()方法定义了该线程的操作和功能。
d) 阻塞状态
i. 一个正在执行的线程在某些特殊情况下,如被人为挂起,将让出CPU并暂时中止自己的执行,进入阻塞状态。在可执行状态下,如果调用sleep(2000)、wait()等方法,线程都将进入阻塞状态。阻塞时,线程不能进入排队队列,只有当引起阻塞的原因被消除后,线程才可以转入就绪状态。
e) 死亡状态
i. 线程调用stop()方法时或run()方法执行结束后,线程即处于死亡状态。处于死亡状态的线程不具有继续运行的能力。//线程池 可以让线程起死回生

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wwwjfplus

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值