并发与线程基础

实现线程的两种方法:

1. 类A继承Thread类: //具体例子:书《从零开始写Java web框架》P159

Thread thread1 = new Thread(){
   // 代码块
}
//实际就是代码块继承new后声明的类,然后用对象接收(可重写覆盖某方法)

2.实现Runnable 接口: 

Thread t=new Thread(
    new Runnable() { 
            //定义匿名内部类,该类实现Runnable接口
            @Override
            public void run() {//实现run()
            }
    }
}

线程的创建:

new Thread()
new Thread(String name)  
new Thread(Runnable target)   
new Thread(Runnable target,String name)

 Thread线程的方法:

Void start() //启动线程
		//类A.start()--相当于执行类A里重写的run()方法,但即使多个run仍是单线程
		//实现线程的两种方法都通过此方法启动线程
static void sleep(long millis) //线程休眠 多少毫秒
static void sleep(long millis,int nanos) //线程休眠 多少毫秒 精确到纳秒		
void join()  //使其他线程等待,等待当前线程停止
void join(long millis)  //使其他线程等待多长毫秒
void join(long millis,int nanos)  //使其他线程等待多长毫秒,可精确到纳秒
static void yield()  //当前运行线程释放处理器的资源
static Thread currentThread()  //返回当前运行的线程引用
		//例 Thread.currentThread().getName()返回字符串 Thread-数(第几个线程数)

如何正确的停止线程的方法:(错误的停止的方法是stop()方法)

interrupt();//会使得线程Waiting和Timed_Waiting状态的线程抛出 interruptedException异常
Thread.interrupt();//其书写所在线程停止
A.interrupt() //类A线程停止	//类A继承 Thread类
A.isInterrupted() 返回true 表类A线程停止
Thread.currentThread.interrupt()	//其书写所在线程是否停止

多个start()多个线程,从程序来说,是同时运行的,会执行方法1一部分,再执行方法2一部分,都没谱
对于cpu则是选择性执行方法,即
两个start()里都为无限循环,方法1执行某部分,方法2执行某部分,以此类推.(断点,循环次数,没谱任意)
wait 与 notifyAll:

    示例
        不同线程引用改变同一变量会变脏数据(即枪临界资源)
        临界资源--就相当于打印机

synchronized(变量){
    变量.wait();---不参与变量的抢夺
}
其后代码不运行,唤醒会执行唤醒在另一个run里
synchronized(变量){
    变量.notifyAll();
}
//notify()方法仅唤醒一个线程(等待队列中的第一个线程)并允许他去获得锁.notifyAll()方法唤醒所有等待这个对象的线程并允许他们去竞争获得锁

sleep与 wait区别:
        sleep需要设置过期时间(时间到了自然执行),wait可设置时间,或不设置时间,不设置时间时通过notify()|notifyAll()方法去唤醒
        调用sleep()方法并不会释放锁.而wait()方法则不同,当调用wait()方法后,线程会释放掉他所占用的锁,从而使线程所在对象中的         其他synchronized数据可以被其他线程使用。
        即sleep不会释放锁;而wait会,从而使synchronized数据可以被其他线程使用。
        sleep()方法可以在任何地方使用。
        wait()方法只能在synchronized方法或synchronized块中使用。

        在main里执行start,要带new 关键字!?
        run方法引用方法为例    public synchronized void name() {}
        synchronized 会对包含此方法的'[类]'加锁。

synchronized:
        即多个线程引用的'[类]'为同一'对象',当一个线程用带synchronized的方法时(其余方法不受影响),别的线程用不了,需等待其执         行完;不同'对象'不会等,会同时运行程序。
        提示-当有需要解决的问题时,内部类(结合构造方法)可解决.。
        static synchronized,找的是类,类同冲突会锁住的;不是 synchronized 的类对象;两者不会冲突static synchronized与                         synchronized的方法。


争用条件 (race Condition):
        当多个线程同时共享访问统一数据(内存区域)时,每个线程都尝试操作该数据,从而导致数据被破坏(corrupted),这           种现象被称为争用条件。
    使用/示例:

public String getSyso(String js) {
	final ArrayList<Integer> list = new ArrayList<Integer>();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        list.add(5);
        Thread thread1 = new Thread(){
            public void run() {
                Iterator<Integer> iterator = list.iterator();//list是变量名
                while(iterator.hasNext()){
                    Integer integer = iterator.next();
                    try {
		        Thread.sleep(500);
		    } catch (InterruptedException e) {
			 // TODO Auto-generated catch block
			 e.printStackTrace();
		    }
                }
            }
        }
        Thread thread2 = new Thread(){
            public void run() {
                Iterator<Integer> iterator = list.iterator();
                while(iterator.hasNext()){
                    Integer integer = iterator.next();
                }
            }
        }
        thread1.start();
	thread2.start();
}
			

ThreadLocal:

    线程局部变量//使多个线程引入同一对象,其属性不互相影响
    实现原理 线程做key的一个Map

    使用/示例:

         线程共享可变数据,看如下:
             同步:多个线程引用的外部同一内容由关键字 synchronized 修饰,叫同步数据(即阻塞,见下157行), volatile 使读取时是实时的。
            名词解释
                原子性: 一个非long|double的变量,另个线程已经改过此变量(无 synchronized 修饰),这一瞬间此线程又读取此变量,可读取到已经改后的值 (即读取此变量时可获取在另线程更改后的值(但不保证,可用 volatile 修饰此原子性变量,解决使能"实时看到"此变量值))
                非原子性:例(num++操作此会有多步骤;读写先后执行)如:第二个线程在第一个线程读后写回新值期间,读取会得到与第一线程读取相同的值,此时就要用 synchronized 修饰锁资源解决了(此时就是非原子 性了)    
            用volatile修饰的原子性变量,就不要synchronized修饰了;缺陷:此变量++操作时(是非原子性的),数据可能会出错
        集合
             CopyOnWriteArrayList 同list使用;CopyOnWriteArraySet同 set 使用;ConcurrentMap 猜同 map
             用上别用同步在并发中
        同步器 常用CountDownLatch和Semaphore    //使线程能够等待另一个线程的对象
        倒计数锁存器 CountDownLatch        
            是一次性的障碍,允许一个或者多个线程等待一个 ,或者多个其他线程来做某些事情。
            CountDownLatch的唯一构造器带有一个int类型的参数,这个int参数是指允许所有在等待的线程被处理之前,必须在锁存器上调用countDown方法的次数。


工作队列:
        创建
            ExecutorService executor = Executors.newSingleThreadExecutor();
        执行踢脚一个runnable方法
            executor.execute(runnable);
        终止    
            executor.shutdown();

线程池:
        如果想让不止一个线程来处理来自这个队列的请求,只要调用一个不同的静态工厂,
        这个工厂创建了一种不同的执行服务,称作线程池(thread pool)

通过线程池来创建和管理多线程: JDK5提供了 Concurrent 并发工具包
        常用线程池
            Executors.newCachedThreadPool 可缓存的线程池。如果线程池的大小超过了处理任务所需要的线程,那么就会回收部分空闲(60秒不执行任务)的线程,当任务数增加时,此线程池又可以智能的添加新线程来处理任务。此线程池不会对线程池大小做限制,线程池大小完全依赖于操作系统(或者说JVM)能够创建的最大线程大小。
            Executors.newFixedThreadPool 固定大小的线程池。每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小。线程池的大小一旦达到最大值就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程。?
            Executors.newSingleThreadExecutor 单线程的线程池,此线程池保证所有任务的执行顺序按照任务的提交顺序执行。
            Executors.newScheduledThreadPool 大小无限制的线程池。此线程池支持定时以及周期性执行任务,例 JAVA\其它\后台配置\定时任务.txt
        线程池使用
            1. 通过ExecutorService接口的submit方法提交一个实现Callable/Runnable接口的类,可获取一个Future接口的对象,通过Future接口的get方法获取Callable任务的执行结果,可设置超时时间。
            2. 通过Executor接口的execute方法提交一个实现Runnable接口的类,不可通过Future获取执行结果,不可设置超时时间。    
java.util.Timer被    Executor Framework中的    ScheduledThreadPoolExecutor替代(原因p240)        
线程组(ThreadGroup)-已过时,毫无用处,所提供的方法都有更好的实现方法


线程和进程各自有什么区别和优劣呢?
    进程是资源分配的最小单位,线程是程序执行的最小单位
    进程有自己的独立地址空间,每启动一个进程,系统就会为它分配地址空间,建立数据表来维护代码段、堆栈段和数据段,这种操作非常昂贵。而线程是共享进程中的数据的,使用相同的地址空间,因此CPU切换一个线程的花费远比进程要小很多,同时创建一个线程的开销也比进程要小很多。
    线程之间的通信更方便,同一进程下的线程共享全局变量、静态变量等数据,而进程之间的通信需要以通信的方式(IPC)进行。不过如何处理好同步与互斥是编写多线程程序的难点。
    但是多进程程序更健壮,多线程程序只要有一个线程死掉,整个进程也死掉了,而一个进程死掉并不会对另外一个进程造成影响,因为进程有自己独立的地址空间
Java的线程生命周期有六种状态
    New(初始化状态) 线程其实是还没被创建的,所以这个时候是不可能分配CPU执行这个线程的
    Runnable(可运行/运行状态)    分配CPU执行了,在New状态时候我们调用start()方法后线程就处于这个状态
    Blocked(阻塞状态)    不分配CPU执行,即被 synchronized 修饰的方法或者代码块同一时刻只能有一个线程执行,而其他竞争锁的线程就从Runnable到了Blocked状态!当某个线程竞争到锁了它就变成了Runnable状态。注意并发包中的 Lock,是会让线程属于等待状态而不是阻塞,只有synchronized是阻塞
    Waiting(无时间限制的等待状态)    
        不分配CPU执行
        调用无参的Object.wait()方法。等到notifyAll()或者notify()唤醒就会回到Runnable状态。
        调用无参的Thread.join()方法。也就是比如你在主线程里面建立了一个线程A,调用A.join(),那么你的主线程是得等A执行完了才会继续执行,这是你的主线程就是等待状态。
        调用LockSupport.park()方法。LockSupport是Java6引入的一个工具类Java并发包中的锁都是基于它实现的,再调用LocakSupport.unpark(Thread thread),就会回到Runnable状态
    Timed_Waiting(有时间限制的等待状态)
        就是有时间的等待,不分配CPU执行
        Object.wait(long timeout)。
        Thread.join(long millis)。
        Thread.sleep(long millis)。注意 Thread.sleep(long millis, int nanos) 内部调用的其实也是Thread.sleep(long millis)。
        LockSupport.parkNanos(Object blocked,long deadline)。
        LockSupport.parkUntil(long deadline)
    Terminated(终止状态)
        在我们的线程正常run结束之后或者run一半异常了就是终止状态!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值