博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
java多线程知识点汇总(二)多线程实例解析
阅读量:5294 次
发布时间:2019-06-14

本文共 4075 字,大约阅读时间需要 13 分钟。

本实验主要考察多线程对单例模式的操作,和多线程对同一资源的读取,两个知识。实验涉及到三个类:

1)一个pojo类Student,包括set/get方法。

2)一个线程类,设置student的成员变量age和name的值为111和111

3)另一个线程类,设置student的成员变量age和name的值为222和2222

4)main类,for循环200次,分别创建200个线程1和线程2对同一资源访问。(共400个线程)

 

1.第一种情况:饿汉式单例模式保证多线程操控的是同一对象

//饿汉式单例模式pojo类 public class Student {    private String age = "12";    private String name = "Tome";        private static Student student = new Student();//类加载时候创建对象        public String getNameAndAge() {        return name+":"+age;    }     public void setNameAndAge(String name,String age) {        this.name = name;        this.age = age;    }    private Student() //构造函数私有化    {            }    public static Student GetInstace() { //方法区函数,静态函数            return student;    }}

线程2类:

public class MyThread extends Thread {    @Override    public void run() {        // TODO Auto-generated method stub        System.out.println(Student.GetInstace().hashCode());    }}

测试类,创建并启动400个线程:

public class AppMain implements Runnable{    public static void main(String[] args) {        AppMain appMain = new AppMain();        for(int i =0;i<200;i++)        {        Thread thread1 = new Thread(appMain);//线程1        MyThread thread2 = new MyThread();//线程2        thread1.start();        thread2.start();        }    }        @Override    public void run() {        // TODO Auto-generated method stub        System.out.println(Student.GetInstace().hashCode());    }}

结果:

 

2.第二种情况:共享资源的写方法不设置任何同步,多个线程可以交叉写数据

public String getNameAndAge() {        return name+":"+age;    }     public void setNameAndAge(String name,String age) { //没有设置任何写同步        this.name = name;        this.age = age;    }

俩线程操控类:

public class MyThread extends Thread {    @Override    public void run() {        // TODO Auto-generated method stub        Student.GetInstace().setNameAndAge("111", "111");//设置name和age值为1         System.out.println(Student.GetInstace().getNameAndAge(););    }}

线程2

public class AppMain implements Runnable{   public static void main(String[] args) {        AppMain appMain = new AppMain();        for(int i =0;i<200;i++)        {        Thread thread1 = new Thread(appMain);        MyThread thread2 = new MyThread();        thread1.start();        thread2.start();        }    }        @Override    public void run() {        // TODO Auto-generated method stub        Student.GetInstace().setNameAndAge("222", "2222");//设置name和age为2         System.out.println(Student.GetInstace().getNameAndAge(););    }}

执行结果:

3.第三种情况:共享资源的写方法设置同步synchronized,保证同一时刻只有一个线程才能执行写,执行完后才释放锁。

public String getNameAndAge() {        return name+":"+age;    }    synchronized public void setNameAndAge(String name,String age) { //写方法设置synchronized了        this.name = name;        this.age = age;    }

测试类添加打印:

public static void main(String[] args) {        AppMain appMain = new AppMain();        for(int i =0;i<200;i++)        {        Thread thread1 = new Thread(appMain);        MyThread thread2 = new MyThread();        thread1.start();        thread2.start();        System.out.println(Student.GetInstace().getNameAndAge());//添加打印,显示name和age值        }    }

这样就能多个线程按序设置name和set值了。但为什么测试结果依然有脏数据呢?比如111:222这种脏数据呢?

答案:因为没设置单例对象读get方法的锁,这样读方法可以随时获取值,即使set线程还没执行完,因为没有synchronized限制可以随时访问。

4.第四种情况,共享资源的读方法不同步不synchronized,方便随时读取不受锁的限制。但就像之前说的,会读到写线程还没执行完时的数据,造成数据混乱。因为读线程可以随时读,没有锁的限制。

public String getNameAndAge() { //读方法没有做同步synchronized处理,可以随时读取,就可以读出写线程未执行完的中间数据        return name+":"+age;    }    synchronized public void setNameAndAge(String name,String age) {        this.name = name;        this.age = age;    }

操作结果:

5.第五种情况,读方法也设置synchronized,锁的对象也是this。保证写的时候不能读,保证读的时候不能写。即读写用同一个锁。

synchronized public String getNameAndAge() {        return name+":"+age;    }    synchronized public void setNameAndAge(String name,String age) {        this.name = name;        this.age = age;    }

测试结果:

这样数据就全部准确了,但是这样效率很低,因为读写共同设置一个锁。读的时候不能写,写的时候不能读。全部都是按序来访问。

结论:当多线程共同访问同一资源时候,此共享对象的读写方法,要都设置同一个锁,保证写的时候不能读,读的时候不能写,且读写都是按序执行。才能保证数据的准确性。

同时,也说明了,没有设置锁的方法可以随时执行,随时执行,随时可能被cpu调度以至打断线程的执行,以至读到线程执行一半产生的脏数据。

转载于:https://www.cnblogs.com/panxuejun/p/5920450.html

你可能感兴趣的文章
Segmentation fault(Core Dump)
查看>>
SQL Server全文索引 (简单的搜索引擎)
查看>>
关于logstash-out-mongodb插件说明
查看>>
第三届蓝桥杯本科预赛 c++ 第十题
查看>>
redis详解
查看>>
修改列名以及其数据类型
查看>>
实用性较强的idea插件
查看>>
鱼塘钓鱼(fishing)
查看>>
java基础篇---正则表达式
查看>>
声明提升
查看>>
关于c# .net爬虫
查看>>
Rails--render partial时传递参数
查看>>
java基础不牢固容易踩的坑
查看>>
P4824 [USACO15FEB]Censoring (Silver) 审查(银)
查看>>
实验二
查看>>
记录一些IDEA常用的快捷键和技巧 二(界面布局)
查看>>
log4j的简单应用(转载)
查看>>
iOS UILabel自定义行间距
查看>>
git命令详解(一)
查看>>
【模板】埃筛
查看>>