1.方法内的变量为线程安全
public class HasSelfPrivateNum {
public void addI(String userName){
try{
int num = 0;
if(userName.equals("a")){
num = 100;
System.out.println("a set over!");
Thread.sleep(2000);
}else{
num = 200;
System.out.println("b set over!");
}
System.out.println(userName + " = " + num);
}catch(InterruptedException e){
e.printStackTrace();
}
}
}
public class ThreadA extends Thread{
private HasSelfPrivateNum numRef;
public ThreadA(HasSelfPrivateNum numRef){
// super();
this.numRef = numRef;
}
public void run(){
// super.run();
numRef.addI("a");
}
}
public class ThreadB extends Thread{
private HasSelfPrivateNum numRef;
public ThreadB(HasSelfPrivateNum numRef){
this.numRef = numRef;
}
public void run(){
numRef.addI("b");
}
}
public class MainFunction {
public static void main(String[] args) {
HasSelfPrivateNum numRef = new HasSelfPrivateNum();
ThreadA threadA = new ThreadA(numRef);
ThreadB threadB = new ThreadB(numRef);
threadA.start();
threadB.start();
}
}
结果:
结论:方法中非变量不存在非线程安全问题,永远是线程安全的。这是方法内部的变量是私有的特性造成的。
=========================================
2.实例变量非线程安全
public class HasSelfPrivateNum {
private int num = 0;
public void addI(String userName){
try{
if(userName.equals("a")){
num = 100;
System.out.println("a set over!");
Thread.sleep(2000);
}else{
num = 200;
System.out.println("b set over!");
}
System.out.println(userName + " = " + num);
}catch(InterruptedException e){
e.printStackTrace();
}
}
}
仅修改以上代码,其余与1同。
结果:
将上述代码加上synchronized关键字:
public class HasSelfPrivateNum {
private int num = 0;
synchronized public void addI(String userName){
try{
if(userName.equals("a")){
num = 100;
System.out.println("a set over!");
Thread.sleep(2000);
}else{
num = 200;
System.out.println("b set over!");
}
System.out.println(userName + " = " + num);
}catch(InterruptedException e){
e.printStackTrace();
}
}
}
结果:可以看到的是,变成同步执行了(先执行哪个线程,就需要等这个线程执行完后才会执行下一个线程)
结论:在两个线程访问同一个对象中的同步方法时一定是线程安全的。
3.多个对象多个锁
代码在2的基础上,修改测试方法:
public class MainFunction {
public static void main(String[] args) {
HasSelfPrivateNum numRef1 = new HasSelfPrivateNum();
HasSelfPrivateNum numRef2 = new HasSelfPrivateNum();
ThreadA threadA = new ThreadA(numRef1);
ThreadB threadB = new ThreadB(numRef2);
threadA.start();
threadB.start();
}
}
测试结果:
结论:关键字synchronized取得的锁都是对象锁,而不是把一段代码或方法当作锁,所以在上述示例中,哪个线程先执行带synchronized关键字的方法,哪个线程就持有该方法所属对象的锁Lock,那么其他线程只能呈等待状态,但前提是多个线程访问的是同一个对象!!
4.synchronized方法与锁对象
public class MyObject {
synchronized public void methodA(){
try{
System.out.println("begin methodA threadName="+
Thread.currentThread().getName());
Thread.sleep(5000);
System.out.println("end" +
" time="+System.currentTimeMillis());
}catch(InterruptedException e){
e.printStackTrace();
}
}
public void methodB(){
try{
System.out.println("begin methodB threadName="+
Thread.currentThread().getName() +
"begin time="+System.currentTimeMillis());
Thread.sleep(5000);
System.out.println("end");
}catch(InterruptedException e){
e.printStackTrace();
}
}
}
public class ThreadA extends Thread{
private MyObject myObject;
public ThreadA(MyObject myObject){
this.myObject = myObject;
}
public void run(){
myObject.methodA();
}
}
public class ThreadB extends Thread{
private MyObject myObject;
public ThreadB(MyObject myObject){
this.myObject = myObject;
}
public void run(){
myObject.methodB();
}
}
public class Run {
public static void main(String[] args) {
MyObject myObject = new MyObject();
ThreadA a = new ThreadA(myObject);
a.setName("A");
ThreadB b = new ThreadB(myObject);
b.setName("B");
a.start();
b.start();
}
}
运行结果:
将上述MyObject类中的methodB()方法中加入synchronized关键字后再测试结果如下
结论:
1)A线程先持有object对象的Lock锁,B线程可以以异步的方式调用object对象中的非synchronized类型的方法;
2)A线程先持有object对象的Lock锁,B线程如果在这时调用object对象中的synchronized类型的方法则需等待,也就是同步。
5.脏读
public class PublicVar {
private String username="A";
private String password="AA";
synchronized public void setValue(String username,String password){
try{
this.username = username;
Thread.sleep(5000);
this.password=password;
System.out.println("setValue method thread name="
+ Thread.currentThread().getName()+
" username="+username+" password="+password);
}catch(Exception e){
e.printStackTrace();
}
}
public void getValue(){
System.out.println("getValue method thread name="
+ Thread.currentThread().getName()+
" username="+username+" password="+password);
}
}
public class ThreadA extends Thread{
private PublicVar publicVar;
public ThreadA(PublicVar publicVar){
this.publicVar = publicVar;
}
public void run(){
publicVar.setValue("B", "BB");
}
}
public class Test {
public static void main(String[] args) {
try{
PublicVar publicVar = new PublicVar();
ThreadA a = new ThreadA(publicVar);
a.start();
Thread.sleep(200);//打印结果受此值大小影响
publicVar.getValue();
}catch(Exception e){
e.printStackTrace();
}
}
}
结果:
将PublicVar类中的getValue()方法加上synchronized关键字后:
结论:要理解对象锁这个概念。简单来说就是当线程A获取了对象锁后,其他线程可以访问该对象的非synchronized方法。而如果该对象的所有方法都有synchronized修饰,则其他线程访问该对象时都要等A线程执行完后才可以访问。即对象锁的概念。
6.synchronized锁重入
可重入锁的概念是:自己可以再次获取自己的内部锁。(也支持在父子类继承环境中。)7.出现异常,锁自动释放
8.同步不具有继承性
public class Main {
synchronized public void serviceMethod(){
try{
System.out.println("int Main 下一步 sleep begin threadName=" +
Thread.currentThread().getName() +
" time=" + System.currentTimeMillis());
Thread.sleep(5000);
System.out.println("int Main 下一步 sleep end threadName=" +
Thread.currentThread().getName() +
" time=" + System.currentTimeMillis());
}catch(Exception e){
e.printStackTrace();
}
}
}
public class Sub extends Main{
public void serviceMethod(){
try{
System.out.println("int Sub 下一步 sleep begin threadName " +
Thread.currentThread().getName() +
" time=" + System.currentTimeMillis());
Thread.sleep(5000);
System.out.println("int Sub 下一步 sleep end threadName " +
Thread.currentThread().getName() +
" time=" + System.currentTimeMillis());
super.serviceMethod();
}catch(Exception e){
e.printStackTrace();
}
}
}
public class ThreadA extends Thread{
private Sub sub;
public ThreadA(Sub sub){
this.sub = sub;
}
public void run(){
sub.serviceMethod();
}
}
public class ThreadB extends Thread{
private Sub sub;
public ThreadB(Sub sub){
this.sub = sub;
}
public void run(){
sub.serviceMethod();
}
}
public class Test {
public static void main(String[] args) {
Sub sub = new Sub();
ThreadA a = new ThreadA(sub);
a.setName("a");
a.start();
ThreadB b = new ThreadB(sub);
b.setName("b");
b.start();
}
}
结果:(非同步调用)
修改:在Sub类的方法上加上synchronized后再运行:(可以看到是同步调用)