java多线程学习

参考:

http://blog.csdn.net/stellaah/article/details/6798244

http://bbs.csdn.net/topics/300116354

http://blog.csdn.net/ghsau/article/details/7421217

http://blog.csdn.net/sd0902/article/details/8395677

创建线程:

创建线程过程:
1.继承Thread

class 类名A extends Thread
{
public void run(){}
}

2.实例对象
Thread t=new 类名A();

3.启用线程
t.start();自动会去运行run().

  

2.Runable接口

实现Runnable接口创建线程

1.实现Runnable接口
类名A implements Runnable()
{
	public void run(){}
}

2.启用线程
new Thread(类名A的对象).start();

区别:

使用Runnable接口创建多线程,适合多个相同的程序代码的线程去处理分享同一个资源的情况,把虚拟CPU(线程)同程序的代码数据有效分离,较好体现了面向对象的设计思想.

setDeamon(true)

设置守护线程,程序非守护线程全部退出时,守护线程自动退出。

join(),join(msecond) 合并线程(如何实现一个线程执行中让另一个线程先执行然后再继续执行自己)

t1.join(500) 打断当前线程执行t1线程,500msecond 如果t1线程死亡 则直接继续执行当前线程

package com.thread;
public class JoinThread
{
    public static void main(String[]args)
    {
        Thread o=new OneThread();
//        o.start();
        
        int index=0;
        while(true)
        {
            System.out.println("main->>"+index+"  "+Thread.currentThread().getName());
            try {
                Thread.sleep(500);
            } catch (InterruptedException e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }
            if(index++==3)
            {
                try
                {
                    o.start();
                    o.join();//把o对应的线程合并10000毫秒    
                }
                catch(Exception e)
                {
                    e.printStackTrace();//输出导致异常更为详细的信息
                }
            }
        }
    }
}


class OneThread extends Thread
{
    public void run()
    {
        
        int i = 1; 
        while(++i<10)
        {
            System.out.println("OneThread->>"+Thread.currentThread().getName());
            try {
                Thread.sleep(500);
            } catch (InterruptedException e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }
        }
    }    
}

/*
运行的结果:
先是两个线程交替执行,main()方法的线程被执行30次后执行run方法的线程.
run方法被执行10000毫秒后就变为刚开始时的样子---两个线程交替执行.
*/

Yield()

在多线程程序中,为了防止某线程独占CPU资源(这样其它的线程就得不到"响应"了).可以让当前执行的线程"休息"一下.但是这种thread.yield() 调用,并不保证下一个运行的线程就一定不是该线程.

public class Test extends Thread {   
  public static void main(String[] args) {   
    for (int i = 1; i <= 2; i++) {   
      new Test().start();   
    }   
  }   
  
  public void run() {   
    System.out.print("1");   
    yield();   
    System.out.print("2");   
  }   
}  
    输出结果: 1122 或者 1212

synchronized

synchronized代码块的用法-synchronized(Object){}

synchronized方法的用法需要与run()方法两个结合起来用

wait() notify

wait()休眠放弃资源控制锁

notify 唤醒在此对象监视器上等待的单个线程。如果所有线程都在此对象上等待,则会选择唤醒其中一个线程。选择是任意性的,并在对实现做出决定时发生。

notifyAll()  唤醒在此对象监视器上等待的所有线程

Timer TimerTask

自JDK5之后,可以用ScheduledThreadPoolExecutor来替代Timer。

ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(3);// 效果类似于Timer定时器

import java.util.*;
class ZhaDan extends TimerTask  //炸弹
{
	public void run()
	{
		System.out.println("Boang... ...炸了!");
	}	
}

class TimerTest
{
	public static void main(String[]args)
	{
		Timer t=new Timer();//创建定时器对象
		ZhaDan z=new ZhaDan();//创建炸弹对象
		t.schedule(z,1000,2000);//隔1秒引爆炸弹.之后就是每2秒一炸

	while(true)
	{
		try{Thread.sleep(1000);}catch(Exception e){}
		System.out.println(new Date().getSeconds());//输出当前时间的秒
		
	}

	}
	
}

 

中断线程  

while(flag)

用thread.interrupt()
或ThreadPoolExecutor.shutdown()

package cn.com.interrupt;

import java.util.Scanner;

public class Test extends Thread {
    private String name;
    
    public Test(String name) {
        this.name = name;
    }
    
    public void write() {
        System.out.print(name);
    }
    
    public static void main(String[]args) throws Exception{
        Thread  t1=new Test("myThread");
        t1.start();
        Scanner sc=new Scanner(System.in);
        String s;

    
        Thread.sleep(5000);
        t1.interrupt();
    }
    
   
    public void run() {
                for(int i=0;;i++){
                if(this.isInterrupted()){
                    System.out.println("exit*****************");
                    return;
                }
                write();
                System.out.println();

        }
    }
    
}

 线程同步问题首先要说明Java线程的两个特性:可见性,有序性

 每个线程都有自己的工作内存(线程栈),工作内存存储了主内存Count对象的一个副本,当线程操作Count对象时,首先从主内存复制Count对象到工作内存中,然后执行代码count.count(),改变了num值,最后用工作内存Count刷新主内存Count。当一个对象在多个内存中都存在副本时,如果一个内存修改了共享变量,其它线程也应该能够看到被修改后的值,此为可见性

多个线程执行时,CPU对线程的调度是随机的,我们不知道当前程序被执行到哪步就切换到了下一个线程,一个最经典的例子就是银行汇款问题,一个银行账户存款100,这时一个人从该账户取10元,同时另一个人向该账户汇10元,那么余额应该还是100。那么此时可能发生这种情况,A线程负责取款,B线程负责汇款,A从主内存读到100,B从主内存读到100,A执行减10操作,并将数据刷新到主内存,这时主内存数据100-10=90,而B内存执行加10操作,并将数据刷新到主内存,最后主内存数据100+10=110,显然这是一个严重的问题,我们要保证A线程和B线程有序执行,先取款后汇款或者先汇款后取款,此为有序性

synchronized volitile

synchronized:

1.修饰变量

sychronized(obj){

2.修饰方法

void sychronized funA(){

}

每个锁对都有两个队列,一个是就绪队列,一个是阻塞队列,就绪队列存储了将要获得锁的线程,阻塞队列存储了被阻塞的线程,当一个线程被唤醒(notify)后,才会进入到就绪队列,等待CPU的调度,反之,当一个线程被wait后,就会进入阻塞队列,等待下一次被唤醒,这个涉及到线程间的通信,当第一个线程执行输出方法时,获得同步锁,执行输出方法,恰好此时第二个线程也要执行输出方法,但发现同步锁没有被释放,第二个线程就会进入就绪队列,等待锁被释放。一个线程执行互斥代码过程如下:

        1. 获得同步锁;

        2. 清空工作内存;

        3. 从主内存拷贝对象副本到工作内存;

        4. 执行代码(计算或者输出等);

        5. 刷新主内存数据;

        6. 释放同步锁。

        所以,synchronized既保证了多线程的并发有序性,又保证了多线程的内存可见性。

volitile:

修饰变量 不能和final一起修饰

static volatile int i = 0, j = 0;

volatile可以将共享变量的改变直接响应到主内存中,这样保证了主内存中的值一致性可以保证内存可见性,不能保证并发有序性

另 volatile 修饰函数 表示编译器不进行代码优化

线程池

创建一个可重用固定线程集合的线程池

ExecutorService threadPool = Executors.newFixedThreadPool(3);

 

创建一个可根据需要创建新线程的线程池

ExecutorService threadPool = Executors.newCachedThreadPool();

 

创建一个使用单个 worker 线程的 Executor,以无界队列方式来运行该线程

ExecutorService threadPool = Executors.newSingleThreadExecutor();

 

创建一个可安排在给定延迟后运行命令或者定期地执行的线程池。

ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(3);

 

Future Callable

http://openhome.cc/Gossip/DesignPattern/FuturePattern.htm

 Callable接口类似于Runnable,从名字就可以看出来了,但是Runnable不会返回结果,并且无法抛出返回结果的异常,而Callable功能更强大一些,被线程执行后,可以返回值,这个返回值可以被Future拿到,也就是说,Future可以拿到异步执行任务的返回值

Future模式在請求發生時,會先產生一個Future物件給發出請求的客戶,而同時間,真正的目標物件之生成,由一個 新的執行緒持續進行(即 Worker Thread),真正的目標物件生成之後,將之設定至Future之中,而當客戶端真正需要目標物件時, 目標物件也已經準備好,可以讓客戶提取使用。

 

Lock 锁

更广泛,继承类更多
private
Lock lock = new ReentrantLock()
private ReadWriteLock rwl = new ReentrantReadWriteLock();
public interface Lock {
  void lock();
    void lockInterruptibly() throws InterruptedException;
 boolean tryLock();
 boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
   void unlock();
   Condition newCondition();
}

 

public class LockTest {
    public static void main(String[] args) {
        final Outputter1 output = new Outputter1();
        new Thread() {
            public void run() {
                output.output("zhangsan");
            };
        }.start();        
        new Thread() {
            public void run() {
                output.output("lisi");
            };
        }.start();
    }
}
class Outputter1 {
    private Lock lock = new ReentrantLock();// 锁对象
    public void output(String name) {
        // TODO 线程输出方法
        lock.lock();// 得到锁
        try {
            for(int i = 0; i < name.length(); i++) {
                System.out.print(name.charAt(i));
            }
        } finally {
            lock.unlock();// 释放锁
        }
    }
}

 死锁实例::

package com.test;

public class SynchronizedSisuo {

    /**
     * @param args
     */
    public static void main(String[] args) {
        SynchronizedSisuo ss = new SynchronizedSisuo();
        ss.t1.start();
    }

    Thread t1 = new Thread(new Runnable() {

        @Override
        public void run() {
            t1Run();
        }
    });

    Thread t2 = new Thread(new Runnable() {

        @Override
        public void run() {
            t2Run();
        }
    });

    Object obj = new Object();

    public void t1Run() {

        synchronized (obj) {
            System.out.println("1111111>>>pre");
            t2.start();
            try {
                t2.join();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            System.out.println("1111111>>>pos");
        }
    }

    public void t2Run() {
        synchronized (obj) {
            System.out.println("2222222>>>pre");
            System.out.println("2222222>>>pos");
        }
    }
}

 

posted on 2014-03-20 15:42  wjw334  阅读(177)  评论(0编辑  收藏  举报

导航