【线程】JAVA线程

PART ONE:线程的创建

1、线程的创建可以分为两种方式:A)继承Tread类;B)实现Runnable接口

2、两种创建线程的方式区别和联系主要有哪些?

   1)、Java单继承机制,限制了Thread类的使用;然后可以通过实现Runnable接口实现多线程,同时也可继承其他类来实现其他功能;

       2)、Runable可以使用多线程去处理同一资源,同时也增加了程序的健壮性,相同的代码可以被多个线程共享,这是Thread类所不具备的;

3、如买票的经典例子:

public class Test {
    public static void main(String[] args) {
        ThreadTest thread1 = new Test.ThreadTest();
        ThreadTest thread2 = new Test.ThreadTest();
        thread1.start();;
        thread2.start();
        RunableTest runable = new Test.RunableTest();
        new Thread(runable).start();;
        new Thread(runable).start();;
    }
    static class ThreadTest extends Thread{
        private int ticket = 10;
        @Override
        public void run() {
            for (int i = 0; i < 20; i++) {
                if(this.ticket > 0){
                    System.out.println("[" + Thread.currentThread().getName() + "] -- " + this.ticket--);
                }
            }
        }
    }
    static class RunableTest implements Runnable {
        private int ticket = 10;
        public void run() {
            for (int i = 0; i < 20; i++) {
                if(this.ticket > 0){
                    System.out.println("[" + Thread.currentThread().getName() + "] -- " + this.ticket--);
                }
            }
        }
    }
}
View Code

PS:

1、JDK中Thread类也是Runnable接口的子类

2、Thread的run()和start()的关系(JDK源码可知):

start()方法使用native关键字修饰,该关键字表示调用操作系统的底层函数(JNI);

Thread的start()一旦被调用,JVM则会去调用run()方法

 

PART TWO:线程的同步

1、线程同步的两个特性:可见性和有序性

  简单来说,多线程的交互方式往往是通过共享变量的方式来实现。如多线程共享内存中的一个对象,如果某一个线程修改了该对象的某个属性值,对于其他线程而言是可以看到被修改的属性值,即:可见性;

  再如多线程共享内存中的一个对象,如果某一个线程想修改该对象的某个属性值,而同时另外一个线程也想修改这个属性值,为了避免修改冲突,一定要保证修改的先后顺序,即:有序性。

2、Java线程同步的实现:volatile、synchronized、Lock

  2-1、volatile

    1)、确切的说该关键字并不是真正意义上的加锁同步(个人理解);它本质是告诉jvm当前变量在寄存器中的值是不确定的,需要从主存中读取;

    2)、只作用于变量级别;

  2-2、synchronized

    1)、并发线程访问同一个对象实例中synchronized(this) 或 synchronized method()时,一个时间内只能有一个线程得到执行,其他线程必须等待当前线程执行完才能继续执行;

    2)、当一个线程访问一个对象实例中synchronized(this) 或 synchronized method()时,其他线程仍然可以访问对象实例中的非synchronized(this) 或 非synchronized method();

    3)、当一个线程访问一个对象实例中synchronized(this) 或 synchronized method()时,其他线程对该对象实例中的其他synchronized(this) 或 synchronized method()的访问仍将被阻塞;

    4)、不同的对象实例的synchronized方法是不相干扰的。也就是说,其它线程照样可以同时访问相同类的另一个对象实例中的synchronized方法;

    5)、synchronized static是某个类的范围,主要防止多个线程同时访问这个类中的synchronized static method(),它可以对类的所有对象实例起作用;synchronized 是某实例的范围,主要防止多个线程同时访问这个实例中的synchronized 方法;

  2-3、Lock(JDK1.5以上的锁框架)

    1)、ReentrantLock 类实现了 Lock ,它拥有与 synchronized 相同的并发性和内存语义,但是添加了类似锁投票、定时锁等候和可中断锁等候的一些特性。此外,它还提供了在激烈争用情况下更佳的性能。(即:当许多线程都想访问共享资源时,JVM 可以花更少的时候来调度线程,把更多时间用在执行线程上。)

    2)、Lock 和 synchronized 有一点明显的区别:Lock必须在finally块中释放。否则,如果受保护的代码将抛出异常,锁就有可能永远得不到释放,This is very terrible!

 

  2-x、锁的概念:

    每个锁都有两个队列,一个是就绪队列,一个是阻塞队列,就绪队列存储了将要获得锁的线程,阻塞队列存储了被阻塞的线程,当一个线程被唤醒(notify)后,才会进入到就绪队列,等待CPU的调度,反之,当一个线程被wait后,就会进入阻塞队列,等待下一次被唤醒,一个线程执行互斥代码过程如下:

    1). 获得同步锁;

    2). 清空工作内存;

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

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

    5). 刷新主内存数据;

    6). 释放同步锁。

3、Java线程同步的实现

  3-1、volatile(略)

  3-2、synchronized

  

public class Test {
    public static void main(String[] args) {
        final Samp1 samp1_0 = new Samp1();
        Samp1 samp1_1 = new Samp1();
        /*
         * 1. new Thread(samp1_0, "thread-A-0").start();
         * 2. new Thread(samp1_0, "thread-B-0").start();
         * 3. new Thread(samp1_1, "thread-A-1").start();
         * 4. new Thread(new Runnable() { public void run() { samp1_0.base_ticket();} }, "thread-C-0").start();
         * 5. new Thread(new Runnable() { public void run() { samp1_0.ticket();} }, "thread-D-0").start();
         * 6. new Thread(new Runnable() { public void run() { samp1_0.syn_ticket();} }, "thread-E-0").start();
         * 7. new Thread(new Runnable() { public void run() { Samp1.syn_stat_ticket();} }, "thread-F-0").start();
         * 8. new Thread(new Runnable() { public void run() { Samp1.syn_stat_ticket2();} }, "thread-G-0").start();
         * 
         * 1 and 2 == > synchronized 性质1
         * 1 and 3 == > synchronized 性质4
         * 4 and 5 == > synchronized 性质2
         * 4 and 6 == > synchronized 性质3
         * 7 and 8 == > synchronized 性质5
         */
        new Thread(samp1_0, "thread-A-0").start();
        new Thread(samp1_0, "thread-B-0").start();
        new Thread(samp1_1, "thread-A-1").start();
        
        new Thread(new Runnable() { public void run() { samp1_0.base_ticket();} }, "thread-C-0").start();
        new Thread(new Runnable() { public void run() { samp1_0.ticket();} }, "thread-D-0").start();
        new Thread(new Runnable() { public void run() { samp1_0.syn_ticket();} }, "thread-E-0").start();
        new Thread(new Runnable() { public void run() { Samp1.syn_stat_ticket();} }, "thread-F-0").start();
        new Thread(new Runnable() { public void run() { Samp1.syn_stat_ticket2();} }, "thread-G-0").start();
    }
}
public class Samp1 implements Runnable{
        private int ticketNum = 10;
        private static int ticketNum_1 = 10;
        public void base_ticket() {
            synchronized (this) {
                for (int i = 0; i < 20; i++) {
                    if(ticketNum > 0){
                        System.out.println("[" + Thread.currentThread().getName()+"] -- " + ticketNum--);
                    }
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        public void ticket(){
            for (int i = 0; i < 20; i++) {
                if(ticketNum > 0){
                    System.out.println("[" + Thread.currentThread().getName()+"] -- " + ticketNum--);
                }
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        public synchronized void syn_ticket(){
            for (int i = 0; i < 20; i++) {
                if(ticketNum > 0){
                    System.out.println("[" + Thread.currentThread().getName()+"] -- " + ticketNum--);
                }
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        public void run() {
        }
        public synchronized static void syn_stat_ticket(){
            for (int i = 0; i < 20; i++) {
                if(ticketNum_1 > 0){
                    System.out.println("[" + Thread.currentThread().getName()+"] -- " + ticketNum_1--);
                }
            }
        }
        public synchronized static void syn_stat_ticket2(){
            for (int i = 0; i < 20; i++) {
                if(ticketNum_1 > 0){
                    System.out.println("[" + Thread.currentThread().getName()+"] -- " + ticketNum_1--);
                }
            }
        }
    }
View Code

  3-3、Lock

  

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ReentrantLockTest {
    private Lock lock = new ReentrantLock();
    private int count = 0;
    public void sampLock() {
        try {
            lock.lock();
            for (int i = 0; i < 100000; i++) {
                count += 1;
            }
            System.out.println(count);
        } finally {
            lock.unlock();
        }
    }
    public static void main(String[] args) {
        final ReentrantLockTest locktest = new ReentrantLockTest();
        new Thread(new Runnable() {public void run() { locktest.sampLock();}}).start();
        new Thread(new Runnable() {public void run() { locktest.sampLock();}}).start();
    }
}
View Code

PART THREE:线程池

JDK具体的接口以及类的说明可以参看http://automaticthoughts.iteye.com/blog/1612388

简单线程池的代码实现

public class ThreadPoolExecutors {
    //THANKS FOR code4crafer@gmail.com
    private int threadNum;
    //thread safe integer class, flag of current pool's alive thread
    private AtomicInteger threadAlive = new AtomicInteger();
    /**
     * 1、ReentrantLock 类实现了 Lock ,它拥有与 synchronized 相同的并发性和内存语义,但是添加了类似锁投票、定时锁等候和可中断锁等候的一些特性。
     * 2、它还提供了在激烈争用情况下更佳的性能。(换句话说,当许多线程都想访问共享资源时,JVM 可以花更少的时候来调度线程,把更多时间用在执行线程上。)
     */
    private ReentrantLock reentrantLock = new ReentrantLock();
    
    private Condition condition = reentrantLock.newCondition();
    private ExecutorService executorService;
    
    public ThreadPoolExecutors(int threadNum) {
        this.threadNum = threadNum;
        this.executorService = Executors.newFixedThreadPool(threadNum);
    }
    
    public int getThreadAlive() {
        return threadAlive.get();
    }
    public int getThreadNum() {
        return threadNum;
    }
    public void execute(final Runnable runnable) {
        // 判断当前线程池活动线程数是否大于线程池最大线程数
        if (threadAlive.get() >= threadNum) {
            try {
                // 加锁
                reentrantLock.lock();
                while (threadAlive.get() >= threadNum) {
                    try {
                    // 如果当前线程池依然没有空闲线程,则等待,直到线程池有空闲线程,之后释放锁
                        condition.await();
                    } catch (InterruptedException e) {
                    }
                }
            } finally {
                // 释放锁
                reentrantLock.unlock();
            }
        }
        // 增加降低线程池中活动线程数标记
        threadAlive.incrementAndGet();
        // 执行任务
        executorService.execute(new Runnable() {
            public void run() {
                try {
                    //执行任务
                    runnable.run();
                } finally {
                    try {
                        reentrantLock.lock();// 加锁
                        threadAlive.decrementAndGet();// 降低线程池中活动线程数标记
                        condition.signal();// 唤醒线程
                    } finally {
                        // 释放锁
                        reentrantLock.unlock();
                    }
                }
            }
        });
    }
    public boolean isShutdown() {
        return executorService.isShutdown();
    }
    public void shutdown() {
        executorService.shutdown();
    }
}
View Code

 

posted on 2014-12-02 15:03  有个姑娘叫小芳  阅读(198)  评论(0编辑  收藏  举报