您的位置:首页 > 其它

多线程

2015-06-12 17:15 381 查看
1. 进程:一个程序是一个进程,一个程序主函数执行就是一个进程,电脑上可以同时有多个进程同时运行,叫并发。2个CPU4个核一共就能并行4个程序,进程多,按时间片轮转获得资源。

2. 线程:一个进程可以包含多个线程,如启动一个QQ是一个进程,QQ同时可以聊天,可以弹广告消息,线程是进程的一个执行线索,线程数多的时候,线程数跟核数相等就并行,不等就时间片轮转。

3. 进程之间交互通信,不方便,线程之间很很方便(一个进程内的)。

4. 程序运行时,先启动线程,按照代码(线路)来执行。

5. 继承Thread类实现多线程:1. 自己实现的线程类要继承Thread类 2. 重写run()方法,run方法里是该线程要执行的操作。

开启线程方法:new线程类对象,用该对象调用start()方法。start方法会调用ran方法。

              如果直接调用run方法,如果run方法是死循环,就会一直执行run方法,这样就是自己实现的线程的线程一直在跑,

              无法执行其他线程,就是资源都被这个线程占用,这个线程一直在执行,直到执行结束。

              调用start方法会在线程启动前向系统申请资源,分配执行的时间片,申请到cpu后,再调用run()方法执行。

6 .实现Runnable接口: 1.自己实现的线程类要实现Runnable类,Runnable接口中只定义了一个run()方法,2.自己实现的类中实现run()方法。

开启线程方法:new Thread(new RunTread()).start(); 其实是Thread类中有个构造方法 Thread(Runnable runnable)可以传

            实现了Runnable接口的子类,启动线程还是调用了Thread类的start()方法。

            这种方式就是不用继承Thread类,自己实现的线程类可以继承别的类了。

7. start()方法如何申请资源: 源码中可以看成 start方法调用源码中一个native的start0方法来实现资源配置。native方法为java与非java代码交互的关键字,

               如调用c代码,JVM将控制调用本地方法的所有细节,具体看另外native博客。

源码:

public synchronized void start() {
/**
* This method is not invoked for the main method thread or "system"
* group threads created/set up by the VM. Any new functionality added
* to this method in the future may have to also be added to the VM.
*
* A zero status value corresponds to state "NEW".
*/
if (threadStatus != 0)
throw new IllegalThreadStateException();

/* Notify the group that this thread is about to be started
* so that it can be added to the group's list of threads
* and the group's unstarted count can be decremented. */
group.add(this);

boolean started = false;
try {
start0();
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
/* do nothing. If start0 threw a Throwable then
it will be passed up the call stack */
}
}
}

private native void start0();

/**
* If this thread was constructed using a separate
* <code>Runnable</code> run object, then that
* <code>Runnable</code> object's <code>run</code> method is called;
* otherwise, this method does nothing and returns.
* <p>
* Subclasses of <code>Thread</code> should override this method.
*
* @see     #start()
* @see     #stop()
* @see     #Thread(ThreadGroup, Runnable, String)
*/
@Override
public void run() {
if (target != null) {
target.run();
}
}


8. 进程分为前台进程和后台进程 后台进程在主函数(也是个进程)中执行的话,如果主函数进程结束,后台进程也结束,前台进程则不受影响。后台线程也叫守护线程。

public static void main(String[] args) {
Thread t = new Ticket();
t.setDaemon(true);//设置为后台进程
t.start();


9. 线程的联合 join

package weiguoyuan.chainunicom.cn;

class Ticket extends Thread {
public void run() {
while(true) {
System.out.println(Thread.currentThread().getName()+ " );
}
}
}

public class TestThread {

public static void main(String[] args) throws InterruptedException {
Thread t = new Ticket();
t.start();

int i = 0;
while(true) {
i++;
System.out.println(Thread.currentThread().getName());
if(i==10000) {
t.join(6666); //6666为毫秒数 ,将t线程联合过来 只执行t直到6666毫秒过后 恢复
}
}
}

}


10. 例子 经典卖票程序 3窗口卖1000

<1. 3个线程 分别有自己的tickets 这样就卖出了 3000张票

package weiguoyuan.chainunicom.cn;

class Ticket extends Thread {
private int tickets = 1000;
public void run() {
while(tickets>0) {
System.out.println(Thread.currentThread().getName()+ " "+tickets--);
}
}
}

public class TestThread {

public static void main(String[] args) {
new Ticket().start();
new Ticket().start();
new Ticket().start();
}
}


<2. 在tickets上加上static 资源共享 3个线程动作相同 瓜分现象

private static int tickets = 1000;


<3. 线程的同步问题,当多个线程同时进入run()方法中,操作tickets--,如假如当前tickets为1,1,2线程两个线程,1线程先得到时间片判断tickets>0,然后还没执行到tickets--这句代码,2号线程抢到时间片进入run()方法也判断tickets>0,然后执行tickets--,这时tickets已经为0了,结束线程,这时1线程得到时间片执行tickets--,tickets=-1,显然已经出错。

解决办法:用锁锁住run()方法,锁住判断和操作资源,让这两步为一个原子,当一个线程进来判断时,不允许其他进程进入。

     第一种锁: synchronized 同步代码块,同步的 的意思,实现方法:Object类,即每个对象都有2种状态,低电平0和高电平1,synchronized通过有线程进入该方法就改变,传入的对象的状态来锁定一段代码,如有线程进入则改变对象的状态为1,其他进程过来时synchronized判断自己的对象为1则不让该线程进入,进入的线程执行结束后将对象的状态改为0,其他线程才可以进入。

package weiguoyuan.chainunicom.cn;

class Ticket extends Thread {
private int tickets = 1000;
private Object obj;
public void run() {
while(true){
synchronized(obj) {//利用obj上锁
if (tickets>0) {
System.out.println(Thread.currentThread().getName()+ " "+tickets--);
}
}
}
}
}

public class TestThread {

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


第二种锁:synchronized 同步函数

package weiguoyuan.chainunicom.cn;

class Ticket extends Thread {
private int tickets = 1000;
public void run() {
while(true){
saleTickets();//原子性代码抽取成同步函数
}
}
public synchronized void saleTickets() {//这个谁调用synchronized  锁的就是谁 其实这3个线程都用的t这个对象调用该方法来同步
if (tickets>0) {
               System.out.println(Thread.currentThread().getName()+ " "+tickets--);
}
}
}

public class TestThread {

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


还可以用lock接口 主要用到的子类为ReentrantLock 来做同步(主要)有lock()和 unlock()方法 (finally 一定要执行的)

11 死锁问题:比如两个线程 都是要得到磁盘和cpu才能运行,一个得到了磁盘,一个得到了cpu,都不释放资源,谁都运行不了

12 线程之间的通信,Thread类中有 sleep()方法释放cpu和资源,Object类里有 wait(),
notify()方法使当前线程等待和唤醒在此对象监视器上等待的单个线程,Object就是看成资源类(磁盘.notify()队列中一个等待的线程,这个线程就可以得到磁盘了)。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: