关键:多线程同步,有两种角度。

1.从JVM的角度来看,instance  = new instance () 不是一个原子操作,在jvm被分成三步,分配内存,设置intance引用指向实例,初始化,JVM乱序执行。需要考虑线陈并发处理问题。可以通过volatile控制语句的原子性。

2.从多条语句之间的角度来看: if(instance =null) {instance  = new instance ()} 这样两句话,如何保证同步。使用sychornized 关键字。通过锁,保证同步代码块 。

1. 主线程

Static Thread currentThread();  //currentThread() 是Thread类的共有静态方法

Thread t = Thread.currentThread();  //获得主线程

Static void Sleep();  //Thread 类的 静态方法,是当前线程睡眠 , 单位毫秒,可修改单位

2. 线程的实现 :

  1) Runnable 接口

  2)扩展Thread类

class MyThread extends Thread{public int x = 0;public void run(){System.out.println(++x);}
}class R implements Runnable{private int x = 0;public void run(){System.out.println(++x);}
}public class Test {public static void main(String[] args) throws Exception{for(int i=0;i<10;i++){Thread t = new MyThread();t.start();}Thread.sleep(10000);//让上面的线程运行完成R r = new R();for(int i=0;i<10;i++){Thread t = new Thread(r);t.start();}}
}

总结:Thread和Runnable是实现java多线程的2种方式,runable是接口,thread是类,建议使用runable实现java多线程,不管如何,最终都需要通过thread.start()来使线程处于可运行状态。

认识Thread的start和run

1) start:

用start方法来启动线程,真正实现了多线程运行,这时无需等待run方法体代码执行完毕而直接继续执行下面的代码。通过调用Thread类的 start()方法来启动一个线程,这时此线程处于就绪(可运行)状态,并没有运行,一旦得到spu时间片,就开始执行run()方法,这里方法 run()称为线程体,它包含了要执行的这个线程的内容,Run方法运行结束,此线程随即终止。

2) run:

run()方法只是类的一个普通方法而已,如果直接调用Run方法,程序中依然只有主线程这一个线程,其程序执行路径还是只有一条,还是要顺序执行,还是要等待run方法体执行完毕后才可继续执行下面的代码,这样就没有达到写线程的目的。

sleep & yield 
  sleep()方法让线程睡眠一段时间,时间过后,线程才会去争取cpu时间片。 
  Java1.5提供了一个新的TimeUnit枚举,让sleep的可读性更好。 
  yield()方法让线程主动让出cpu,让cpu重新调度以决定哪个线程可以使用cpu。

3. 线程同步:

http://www.cnblogs.com/yyyyy5101/archive/2011/07/20/2112157.html

  1) 同步方法 : synchronize关键字修饰 需要保证同步的方法(临界区)

  2) 同步语句 :  synchronized块

  在synchronized关键字后面,要传一个对象参数,任何线程要进入临界区时必须先要获得该对象的锁,退出临界区时要释放该对象的锁,这样别的线程才有机会进入临界区。 
  临界区和synchronized方法,其原理都是一样的,都是通过在对象上加锁来实现的,只不过临界区来得更加灵活,因为它不光可以对this对象加锁,也可以对任何别的对象加锁。

  在使用Java多线程中会需要使用Synchronized块同步方法。我们不仅可以通过synchronized块来同步一个对象变量。也可以使用synchronized块来同步类中的静态方法和非静态方法。

AD: 2013大数据全球技术峰会低价抢票中

synchronized关键字有两种用法。第一种就是在《使用Synchronized关键字同步类方法》一文中所介绍的直接用在方法的定义中。另外一种就是synchronized块。我们不仅可以通过synchronized块来同步一个对象变量。也可以使用synchronized块来同步类中的静态方法和非静态方法。

synchronized块的语法如下:

  1. public void method()
  2. {
  3. … …
  4. synchronized(表达式)
  5. {
  6. … …
  7. }
  8. }

一、非静态类方法的同步

从《使用Synchronized关键字同步类方法》一文中我们知道使用synchronized关键字来定义方法就会锁定类中所有使用synchronzied关键字定义的静态方法或非静态方法,但这并不好理解。而如果使用synchronized块来达到同样的效果,就不难理解为什么会产生这种效果了。如果想使用synchronized块来锁定类中所有的同步非静态方法,需要使用this做为synchronized块的参数传入synchronized块国,代码如下:

通过synchronized块同步非静态方法

  1. public class SyncBlock
  2. {
  3. public void method1()
  4. {
  5. synchronized(this)  // 相当于对method1方法使用synchronized关键字
  6. {
  7. … …
  8. }
  9. }
  10. public void method2()
  11. {
  12. synchronized(this)  // 相当于对method2方法使用synchronized关键字
  13. {
  14. … …
  15. }
  16. }
  17. public synchronized void method3()
  18. {
  19. … …
  20. }
  21. }

在上面的代码中的method1和method2方法中使用了synchronized块。而第017行的method3方法仍然使用synchronized关键字来定义方法。在使用同一个SyncBlock类实例时,这三个方法只要有一个正在执行,其他两个方法就会因未获得同步锁而被阻塞。在使用synchronized块时要想达到和synchronized关键字同样的效果,必须将所有的代码都写在synchronized块中,否则,将无法使当前方法中的所有代码和其他的方法同步。

除了使用this做为synchronized块的参数外,还可以使用SyncBlock.this作为synchronized块的参数来达到同样的效果。

在内类(InnerClass)的方法中使用synchronized块来时,this只表示内类,和外类(OuterClass)没有关系。但内类的非静态方法可以和外类的非静态方法同步。如在内类InnerClass中加一个method4方法,并使method4方法和SyncBlock的三个方法同步,代码如下:

使内类的非静态方法和外类的非静态方法同步

  1. public class SyncBlock
  2. {
  3. … …
  4. class InnerClass
  5. {
  6. public void method4()
  7. {
  8. synchronized(SyncBlock.this)
  9. {
  10. … …
  11. }
  12. }
  13. }
  14. … …
  15. }

在上面SyncBlock类的新版本中,InnerClass类的method4方法和SyncBlock类的其他三个方法同步,因此,method1、method2、method3和method4四个方法在同一时间只能有一个方法执行。

Synchronized块不管是正常执行完,还是因为程序出错而异常退出synchronized块,当前的synchronized块所持有的同步锁都会自动释放。因此,在使用synchronized块时不必担心同步锁的释放问题。

二、静态类方法的同步

由于在调用静态方法时,对象实例不一定被创建。因此,就不能使用this来同步静态方法,而必须使用Class对象来同步静态方法。代码如下:

通过synchronized块同步静态方法

  1. public class StaticSyncBlock
  2. {
  3. public static void method1()
  4. {
  5. synchronized(StaticSyncBlock.class)
  6. {
  7. … …
  8. }
  9. }
  10. public static synchronized void method2()
  11. {
  12. … …
  13. }
  14. }

在同步静态方法时可以使用类的静态字段class来得到Class对象。在上例中method1和method2方法同时只能有一个方法执行。除了使用class字段得到Class对象外,还可以使用实例的getClass方法来得到Class对象。上例中的代码可以修改如下:

使用getClass方法得到Class对象(每一个加载过的类在JVM中都有Class对象,包括基本数据类型和void关键字)

  1. public class StaticSyncBlock
  2. {
  3. public static StaticSyncBlock instance;
  4. public StaticSyncBlock()
  5. {
  6. instance = this;
  7. }
  8. public static void method1()
  9. {
  10. synchronized(instance.getClass())
  11. {
  12. }
  13. }
  14. }

在上面代码中通过一个public的静态instance得到一个StaticSyncBlock类的实例,并通过这个实例的getClass方法得到了Class对象(一个类的所有实例通过getClass方法得到的都是同一个Class对象,因此,调用任何一个实例的getClass方法都可以)。我们还可以通过Class对象使不同类的静态方法同步,如Test类的静态方法method和StaticSyncBlock类的两个静态方法同步,代码如下:

Test类的method方法和StaticSyncBlock类的method1、method2方法同步

  1. public class Test
  2. {
  3. public static void method()
  4. {
  5. synchronized(StaticSyncBlock.class)
  6. {
  7. }
  8. }
  9. }

注意:在使用synchronized块同步类方法时,非静态方法可以使用this来同步,而静态方法必须使用Class对象来同步。它们互不影响。当然,也可以在非静态方法中使用Class对象来同步静态方法。但在静态方法中不能使用this来同步非静态方法。这一点在使用synchronized块同步类方法时应注意。


对象锁

当使用同步块时,如果方法下的同步块都同步到一个对象上的锁,则所有的任务(线程)只能互斥的进入这些同步块。
Resource1.java演示了三个线程(包括main线程)试图进入某个类的三个不同的方法的同步块中,虽然这些同步块处在不同的方法中,但由于是同步到同一个对象(当前对象 synchronized (this)),所以对它们的方法依然是互斥的。

package com.zj.lock;
import java.util.concurrent.TimeUnit;public class Resource1 {public void f() {// other operations should not be locked...
       System.out.println(Thread.currentThread().getName()+ ":not synchronized in f()");synchronized (this) {for (int i = 0; i < 5; i++) {System.out.println(Thread.currentThread().getName()+ ":synchronized in f()");try {TimeUnit.SECONDS.sleep(3);} catch (InterruptedException e) {e.printStackTrace();}}}}public void g() {// other operations should not be locked...
       System.out.println(Thread.currentThread().getName()+ ":not synchronized in g()");synchronized (this) {for (int i = 0; i < 5; i++) {System.out.println(Thread.currentThread().getName()+ ":synchronized in g()");try {TimeUnit.SECONDS.sleep(3);} catch (InterruptedException e) {e.printStackTrace();}}}}public void h() {// other operations should not be locked...
       System.out.println(Thread.currentThread().getName()+ ":not synchronized in h()");synchronized (this) {for (int i = 0; i < 5; i++) {System.out.println(Thread.currentThread().getName()+ ":synchronized in h()");try {TimeUnit.SECONDS.sleep(3);} catch (InterruptedException e) {e.printStackTrace();}}}}public static void main(String[] args) {final Resource1 rs = new Resource1();new Thread() {public void run() {rs.f();}}.start();new Thread() {public void run() {rs.g();}}.start();rs.h();}
}//匿名内部类

匿名类是不能有名称的类,所以没办法引用它们。必须在创建时,作为new语句的一部分来声明它们。这就要采用另一种形式的new语句,如下所示: new <类或接口> <类的主体> 这种形式的new语句声明一个新的匿名类,它对一个给定的类进行扩展,或者实现一个给定的接口。它还创建那个类的一个新实例,并把它作为语句的结果而返回。要扩展的类和要实现的接口是new语句的操作数,后跟匿名类的主体。如果匿名类对另一个类进行扩展,它的主体可以访问类的成员、覆盖它的方法等等,这和其他任何标准的类都是一样的。如果匿名类实现了一个接口,它的主体必须实现接口的方法。

附带问题:为什么局部内部类(即:定义在方法中的内部,包括匿名内部类),使用的参数必须为final?

答 :局部变量的生命周期与局部内部类的对象的生命周期的不一致性!

假设:
1. 我们在方法内定义了一个 匿名的 Thread 子类,他使用了方法的局部参数,然后我让这个线程运行去,因为是不同的线程,那么当我这个方法的启动线程 的语句执行过了,而且我修改了这个参数或局部变量,那么那个线程启动执行的时候是不是会出现莫名其妙的问题:运行时刻能访问到的变量太难以捉摸了,我是该 复制一份过去给新线程运行时使用还是到时候再来取呢(再来取时已经物是人非了)?

2. 设方法f被调用,从而在它的调用栈中生成了变量i,此时产生了一个局部内部类对象inner_object,它访问了该局部变量i .当方法f()运行结束后,局部变量i就已死亡了,不存在了.但:局部内部类对象inner_object还可能   一直存在(只能没有人再引用该对象时,它才会死亡),它不会随着方法f()运行结束死亡.这时:出现了一个"荒唐"结果:局部内部类对象 inner_object要访问一个已不存在的局部变量i!
Java 为了消除这个编程中可能出现的歧义,使用方法内的内部类时如果访问了方法的参数或局部变量,那么它应该是 final 的。

final 原理,当变量是final时,通过将final局部变量"复制"一份

另详解: http://feiyeguohai.iteye.com/blog/1500108

如果满足下面的一些条件,使用匿名内部类是比较合适的:

?只用到类的一个实例。 ?类在定义后马上用到。

?类非常小(SUN推荐是在4行代码以下)

?给类命名并不会导致你的代码更容易被理解。

在使用匿名内部类时,要记住以下几个原则:

?匿名内部类不能有构造方法。

?匿名内部类不能定义任何静态成员、方法和类。

?匿名内部类不能是public,protected,private,static。

?只能创建匿名内部类的一个实例。

?一个匿名内部类一定是在new的后面,用其隐含实现一个接口或实现一个类。

?因匿名内部类为局部内部类,所以局部内部类的所有限制都对其生效。


4.线程间通信 :

  notify() wait() notifyAll();

Java中如何实现线程同步 
  在Java中,线程的同步涉及到synchronized和三个方法wait()、notify()和notifyAll()。

  synchronized在上篇中已经讲过了,这里就不再重复了。

  wait()方法与Thread类的sleep()和yield()方法类似,都是让当线程睡眠,或者说是暂停执行;与之不同的是wait()方法会释放掉当前对象的锁,也因为此wait()方法必须在synchronized块里才能被调用。

  notify()和notifyAll()方法用于唤醒之前调用wait()方法睡眠的线程,与wait()方法一样,notify()和notifyAll()也必须在synchronized块里才能被调用。

  注意wait()、notify()和notifyAll()三个方法都是Object类的,而不是Thread类的。因为这三个方法都涉及的锁的操作,而锁的操作适用于所有的对象。

转载于:https://www.cnblogs.com/alexlo/archive/2013/03/14/2959507.html

JAVA 基础之 多线程相关推荐

  1. Java基础、多线程、JVM、集合八股文自述(持续更新)

    Java基础.多线程.JVM.集合八股文自述 一.Java基础 1.1 object类有哪些方法? getClass().hashCode().equals().clone().toString(). ...

  2. JAVA基础+集合+多线程+JVM

    1. Java 基础 1.1. 面向对象和面向过程的区别 面向过程性能比面向对象高. 因为类调用时需要实例化,开销比较大,比较消耗资源,所以当性能是最重要的考量因素的时候 等一般采用面向过程开发.但是 ...

  3. java基础学习-多线程笔记

    说说Java中实现多线程有几种方法 创建线程的常用三种方式: 1. 继承Thread类 2. 实现Runnable接口 3. 实现Callable接口( JDK1.5>= ) 4. 线程池方式创 ...

  4. Java基础之多线程详细分析

    在了解多线程之前,先来了解一下进程与线程之间的关系. 进程和线程: 进程是指在系统中正在执行的一个程序,每个进程之间是独立的. 线程是进程的一个基本执行单元.一个进程要想执行任务,必须得有线程(每1个 ...

  5. Java基础之多线程框架

    一.进程与线程的区别 1.定义: 进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位. 线程是进程的一个实体,是CPU调度和分派的基本单位,它是比 ...

  6. Java基础21 多线程线程两种实现方式 锁

    一.多线程的概念 1.程序 :一个固定逻辑与数据的集合 就称为程序 例如淘宝 贪吃蛇小游戏 2.CPU: 中央处理器 主要用于协调程序与硬件进行配置的工作 3.并发与并行 1.并发(高并发) 在同一个 ...

  7. 【Java基础】多线程

    线程及与进程的区别 线程也被称为是轻量级的进程,是程序执行的最小单元.有四种状态:运行,就绪,挂起和结束.一个进程拥有多个线程,这些线程共享进程的一些资源如打开的文件,代码段,数据段和堆空间. 使用线 ...

  8. java基础知识 多线程

    package org.base.practise9; import org.junit.Test; import java.awt.event.WindowAdapter; import java. ...

  9. 8.Java基础之多线程

    1. 回顾 接口 ①方法(分jdk版本) ②多继承 ③变量特点 ④多态的前提之一 ⑤工厂设计模式,起码要知道简单工厂 ⑥vs 抽象类 异常 ①异常的祖宗类:Throwable ②异常的分类:编译(受检 ...

  10. Java基础进阶多线程-生产者和消费者模式

    1.什么是"生产者和消费者模式"? 生产线程负责生产,消费线程负责消费 生产线程和消费线程要达到均衡 这是一种特殊的业务需求,在这种特殊的情况下需要使用wait方法和notify方 ...

最新文章

  1. 01_字符串处理-----03_替换和校正标识符
  2. zqgame《每日一言》
  3. easyui js解析字符串_EasyUI Dialog弹出框+JS执行字符串
  4. 使用NeMo快速完成NLP中的信息抽取任务,英伟达专家实战讲解,内附代码
  5. 2015.08.17 Ubuntu 14.04+cuda 7.5+caffe安装配置
  6. caffe学习笔记25-过拟合原因及分析
  7. SpringMVC的请求-获得请求参数-获得集合类型参数1
  8. C++ POD与结构体声明
  9. 第8章 java中的并发工具类
  10. Linux 系统下命令 unrar 的英文版使用说明
  11. jQuery 之 $(this) 出了什么问题?
  12. vs2015开发activex控件资料
  13. 百问网7天物联网智能家居(第七天)
  14. matlab拟合公式不准确,Matlab拟合函数误差:函数值和YDATA大小不相等
  15. Django Ajax总结
  16. 《清单革命》的读后感优秀范文3900字
  17. 微信小程序tab选项卡,点击弹窗(带蒙版)五星好评-获取微信手机号码
  18. @media媒体查询——详解
  19. TL494制作0-60V/0-20A/BUCK恒流恒压可调稳压电源/效率大于95%
  20. 改变自己:大一摆烂一年后的深入思考

热门文章

  1. 呼吁各行业实现无纸化办公
  2. 给大楼装上转动外壳减少风力作用
  3. 管理感悟:减少代码量的好办法
  4. 删除文件时提示“对于目标文件系统,文件xx过大”的处理办法”的解决办法
  5. C# 结构体转byte数组 结构体转byte[] 结构体、byte数组互转
  6. 服务器内的虚拟机无法上网,VMware虚拟机中无法上网如何解决
  7. ajax存储表单数据,使用ajax json将表单数据存储到数据库php
  8. 荣耀9桌面没有计算机,荣耀9四个隐藏功能,你用过几个?
  9. python视频教程免费慕课网-python视频教程慕课 | 最好的python视频教程谁有
  10. matlab导弹追踪问题垂直逃逸,综合程序设计 导弹追踪问题 (matlab)