Java——单例模式、多线程
单例模式
单例模式是一种常用的软件设计模式。
在它的核心结构中只包含一个被成为单例类的特殊类。通过单例模式可以保证系统中一个类职业一个实例而且该实例易于外界访问,从而方面对实例个数的控制并节约系统资源。
如果希望在系统中某个类的对象只能存在一个,单例模式是最好的解决方案。
单例模式练习
public class Person {
private int id;
//单例模式:整个系统共享一个对象
public Person(int id) {
super();
this.id = id;
}
//测试
public static void main(String[] args) {
Person p1 = new Person(1);
Person p2 = new Person(2);
}
public void test(){
Singleton ton = Singleton.getInstance();
System.out.println(ton.hashCode());
}
}
单例模式的分类
懒汉式
优点:只有调用方法才创建对象,调用之前不会占用内存
缺点:在多线程模式下不安全
懒汉式相关练习:
public class Singleton {
//私有化构造,只有在本类之中才可以new出来。超出本类无法访问
private Singleton(){
}
//全局对象
private static Singleton singleton=null;
//synchronized 如果加上关键字,则一样
// synchronized 如果没有该关键字,则创建了两个线程不同步
//synchronized 它的位置决定了锁的范围
public static synchronized Singleton getInstance(){
//判断全局对象是否为空
if(singleton==null){
try {
//休眠一秒钟
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//如果为空,就创建该类对象
singleton=new Singleton();
}
//如果不为空,就直接返回该对象
return singleton;
}
public static void main(String[] args) {
//多线程操作
//2.直接使用Thread操作
Thread thread = new Thread(){
@Override
public void run() {
// TODO Auto-generated method stub
Singleton ton = Singleton.getInstance();
System.out.println(ton.hashCode());
}
};
thread.start();
Thread thread2 = new Thread(){
@Override
public void run() {
// TODO Auto-generated method stub
Singleton ton2 = Singleton.getInstance();
System.out.println(ton2.hashCode());
}
};
//开启新线程
thread2.start();
// Person p = new Person(0);
// p.test();
// Singleton s = new Singleton();
// System.out.println(s.hashCode());
}
}
饿汉式
跟懒汉式的区别,直接创建对象。
饿汉式不管有没有调用getInstance方法,都会预先在系统中创建一个静态对象
懒汉式不会预先创建对象,只有在第一次调用时才创建对象。
优点:在多线程模式下是安全的
- 缺点:没有调用方法前就加载,会占用系统内存。
饿汉式相关练习:
public class Singleton2 {
//跟懒汉式的区别,直接创建对象
private static Singleton2 ton = new Singleton2();
//私有构造
private Singleton2(){
System.out.println("对象创建成功!");
}
public static Singleton2 getInstance(){
return ton;
}
/**
* 饿汉式不管有没有调用getInstance方法,
* 都会预先在系统中创建一个静态对象。
* 懒汉式不会预先创建对象,只有在第一次调用时,
* 才创建对象。
* 饿汉式
* 优点:在多线程模式下是安全的。
* 缺点:没有调用方法前就加载,会占用系统内存。
* @param args
*/
public static void main(String[] args) {
Singleton2 ton = Singleton2.getInstance();
System.out.println(ton.hashCode());
}
}
线程安全
饿汉式本身就是线程安全的,可以直接用于多线程而不会出现问题的。
懒汉式是非线程安全的,解决方式如下:
关键字:synchronized:可以用来给对象和方法或者代码块加锁,当它锁定一个方法或者一个代码块的时候,同一时刻最多只有一个线程执行这个段代码。
使用双重检测机制实现线程安全的懒汉式
使用静态内部类实现线程安全的单例模式
多线程
public class Ch01 {
/**
* 系统默认情况下只运行主线程
* @param args
*
public static void main(String[] args) {
//主线程中开启两个子线程
Thread1 thread1 = new Thread1();
Thread2 thread2 = new Thread2();
thread1.start();
thread2.start();
}
}
/**
* 多线程类1
* @author alery
*
*/
class Thread1 extends Thread{
/**
* 线程运行期间执行的代码
*/
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("线程1开始运行。。。。。");
//休眠1秒钟
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("线程1 继续执行......");
}
}
/**
* 多线程类2
*/
class Thread2 extends Thread{
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("线程2开始运行。。。。。");
//休眠1秒钟
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("线程2 继续执行......");
}
}
多线程的三种方式
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
/**
* JAVA三种方式实现多线程
* @author Administrator
*
*/
public class ThreadTest implements Runnable,Callable<String>{
public static void main(String[] args) throws InterruptedException, ExecutionException {
// TODO Auto-generated method stub
//主线程打印
// System.out.println("线程编号:"+Thread.currentThread().getId());
// new ThreadA().start();
// Thread thread=new Thread(){
// public void run() {
// System.out.println(Thread.currentThread().getId()+"线程正在运行");
// }
// };
// thread.start();
ThreadTest t=new ThreadTest();
// new Thread(t).start();
// new Thread(new Runnable() {
//
// @Override
// public void run() {
// // TODO Auto-generated method stub
// System.out.println(Thread.currentThread().getId()+"线程正在运行");
// }
// }).start();
//Runnable
// FutureTask<String> task=new FutureTask<String>(t);
// new Thread(task).start();
// //获取call方法返回的内容
// System.out.println(task.get());
//线程池内线程最大数量
int threadMaxCount=10;
//线程池
ExecutorService service=Executors.newFixedThreadPool(threadMaxCount);
//定义一个集合存储runnable
List<Future<String>> list=new ArrayList<Future<String>>();
//开始运行10个线程(这10个多线程是由线程池管理的)
for(int i=0;i<threadMaxCount;i++) {
FutureTask<String> task=new FutureTask<String>(t);
//submit把runnable提交给了线程池
Future<String> f=(Future<String>) service.submit(task);
list.add(task);
}
// service.shutdown();
for(int i=0;i<list.size();i++) {
Future<String> f=list.get(i);
System.out.println(f.get());
}
}
/**
* 2.实现Runnable接口
* 必须重写run方法
* 创建Thread对象,把runnable传递到构造中
* (匿名实现类)
*/
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println(Thread.currentThread().getId()+"线程正在运行");
}
/**
* 3.实现Callable接口
* 重写call方法
* 使用FutureTask类来实现Runnable
* (FutureTask是Runnable的实现类)
* 创建Thread对象,把FutureTask当作Runnable调用了构造参数
* call方法的返回值可以通过FutureTask.get方法得到
* (get方法必须在线程运行之后才可以调用)
* 线程池配合使用比较好
*/
@Override
public String call() throws Exception {
// TODO Auto-generated method stub
String str=Thread.currentThread().getId()+"线程正在运行";
// System.out.println(str);
return str;
}
}
/**
* 1.继承Thread类
* 重写run方法
* (匿名类方式实现)
* @author Administrator
*
*/
class ThreadA extends Thread{
/**
* 当线程start时,会执行run
*/
@Override
public void run() {
// super.run();
// TODO Auto-generated method stub
System.out.println(Thread.currentThread().getId()+"线程正在运行");
}
}
Java——单例模式、多线程的更多相关文章
- 【深入】java 单例模式(转)
[深入]java 单例模式 关于单例模式的文章,其实网上早就已经泛滥了.但一个小小的单例,里面却是有着许多的变化.网上的文章大多也是提到了其中的一个或几个点,很少有比较全面且脉络清晰的文章,于是,我便 ...
- 深入Java单例模式(转)
深入Java单例模式 源自 http://devbean.blog.51cto.com/448512/203501 在GoF的23种设计模式中,单例模式是比较简单的一种.然而,有时候越是简单的东西越容 ...
- Java基础-多线程-②多线程安全问题
什么是线程的安全问题? 上一篇 Java基础-多线程-①线程的创建和启动 我们说使用实现Runnable接口的方式来创建线程,可以实现多个线程共享资源: class Dog implements Ru ...
- Java 单例模式的七种写法
Java 单例模式的七种写法 第一种(懒汉,线程不安全) public class Singleton { private static Singleton instance; private Sin ...
- java单例模式之懒汉式分析
转自:http://blog.csdn.net/withiter/article/details/8140338 今天中午闲着没事,就随便写点关于Java单例模式的.其实单例模式实现有很多方法,这里我 ...
- Java 单例模式探讨
以下是我再次研究单例(Java 单例模式缺点)时在网上收集的资料,相信你们看完就对单例完全掌握了 Java单例模式应该是看起来以及用起来简单的一种设计模式,但是就实现方式以及原理来说,也并不浅显哦. ...
- 单例模式:Java单例模式的几种写法及它们的优缺点
总结下Java单例模式的几种写法: 1. 饿汉式 public class Singleton { private static Singleton instance = new Singleton( ...
- 9种Java单例模式详解(推荐)
单例模式的特点 一个类只允许产生一个实例化对象. 单例类构造方法私有化,不允许外部创建对象. 单例类向外提供静态方法,调用方法返回内部创建的实例化对象. 懒汉式(线程不安全) 其主要表现在单例类在外 ...
- 你真的理解了java单例模式吗?讲别人都忽略的细节!
前言:老刘这篇文章敢做保证,java的单例模式讲的比大多数的技术博客都要好,讲述别人技术博客都没有的细节!!! 1 java单例模式 直接讲实现单例模式的两种方法:懒汉式和饿汉式,单例模式的概念自己上 ...
随机推荐
- FileZilla使用教程
FileZilla使用教程和问题汇总 正式开始之前我还是想闲聊几句,毕竟调试解决这些问题,整整耗了我一天半的时间.前不久学校要求上交一个web大作业,然后我们宿舍就寻思光做出来前后端搞头不大,不如整个 ...
- 线程方法wait()和notify()的使用
实现需求: 开启2个线程,1个线程对某个int类型成员变量加1,另外1个减1,但是要次序执行,即如果int型的成员变量是0,则输出01010101这样的结果 代码如下 1 package test; ...
- linux系统重启后提示An error occurred during the file system check.
一.问题描述 生产环境中一台浪潮NF8480M3外观红灯报警,鉴于无法登陆带外管理口,只能对服务器进行断电重启操作 二.问题现象 重启后进入开机过程并报错,正常来说进入此界面后直接输入root密码即可 ...
- 安卓mbn文件丢失,无法搜索移动信号,工程模式mbn乱改,不用QPST烧录怎样恢复?超简单!
没有root,工程模式乱改mbn配置选项,导致mbn配置丢失,无法搜索移动网络. 重启若干次改配置都无效,清空网络设置无效,恢复出厂无效,recovery三清无效, 不太想拆机root麻烦,QPST配 ...
- JavaScript高级程序设计(第4版)知识点总结
介绍 JavaScript高级程序设计 第四版,在第三版的基础上添加了ES6相关的内容.如let.const关键字,Fetch API.工作者线程.模块.Promise 等.适合具有一定编程经验的 W ...
- 真的,kafka 入门看这一篇准没错!
什么是 Kafka Kafka 是一个分布式流式平台,它有三个关键能力 订阅发布记录流,它类似于企业中的消息队列 或 企业消息传递系统 以容错的方式存储记录流 实时记录流 Kafka 的应用 作为消息 ...
- jxl解析多个excel工作表-java代码
@Override public ResultBean txImportDqKpi(String filePath) { ResultBean rb = new ResultBean(); int s ...
- CopyOnWriteArrayList 读写分离,弱一致性
为什么会有CopyOnWriteArrayList? 我们知道ArrayList和LinkedList实现的List都是非线程安全的,于是就有了Vector,它是基于ArrayList的线程安全集合, ...
- 透过现象看本质:Java类动态加载和热替换
摘要:本文主要介绍类加载器.自定义类加载器及类的加载和卸载等内容,并举例介绍了Java类的热替换. 最近,遇到了两个和Java类的加载和卸载相关的问题: 1) 是一道关于Java的判断题:一个类被首次 ...
- Oracle备份审计表SYS.AUD$和SYS.FGA_LOG$
ORACLE的审计表不可以使用expdp和impdp导出和导入,如果使用,会报如下错误: 需要使用exp和imp进行导出和导出 导出语句: exp " '/ as sysdba' " ...