1、线程
Thread类:
public final String getName():返回该线程的名称
public final void setName(String name):改变线程名称,使之与参数 name
相同
getThreadGroup():返回该线程所属的线程组。
线程控制:
public static void sleep(long millis):线程休眠
public final void join():线程加入( 等待该线程终止)
public static void yeild():线程礼让(暂停当前正在执行的线程对象,并执行其他线程。)
public final void setDaemon(boolean on):后台线程
public final void stop(): 已过时。 该方法具有固有的不安全性。用 Thread.stop 来终止线程将释放它已经锁定的所有监视器
public void interrupt(): 中断线程。
多线程的实现方案:
1)继承Thread类
步骤
A:自定义类MyThread继承Thread类。
B:MyThread类里面重写run()
C:创建对象
D:启动线程
public class MyThread extends Thread {
public void run() {
for (int x = 0; x < 200; x++) {
System.out.println(x);
}
}
}
public class MyThreadDemo {
public static void main(String[] args) {
// run():仅仅是封装被线程执行的代码,直接调用是普通方法
// start():首先启动了线程,然后再由jvm去调用该线程的run()方法。
// IllegalThreadStateException:非法的线程状态异常
// 创建两个线程对象
MyThread my1 = new MyThread();
MyThread my2 = new MyThread();
// 启动线程
my1.start();
my2.start();
}
}
2)实现Runnable接口(实现接口可以避免java单继承带来的局限性)
步骤:
A:自定义类MyRunnable实现Runnable接口
B:重写run()方法
C:创建MyRunnable类的对象
D:创建Thread类的对象,并把C步骤的对象作为构造参数传递
public class MyRunnable implements Runnable {
public void run() {
for (int x = 0; x < 100; x++) {
// 由于实现接口的方式就不能直接使用Thread类的方法了,但是可以间接的使用
System.out.println(Thread.currentThread().getName() + ":" + x);
}
}
}
public class MyRunnableDemo {
public static void main(String[] args) {
// 创建MyRunnable类的对象
MyRunnable my = new MyRunnable();
// 创建Thread类的对象,并把C步骤的对象作为构造参数传递
// Thread(Runnable target, String name)
Thread t1 = new Thread(my, "aa");
Thread t2 = new Thread(my, "bb");
t1.start();
t2.start();
}
}
解决线程安全问题:
1)同步代码块:
synchronized(对象){
需要同步的代码;
}
同步可以解决安全问题的根本原因就在那个对象上。该对象如同锁的功能。多个线程必须是同一把锁。
public class SellTicket implements Runnable {
// 定义100张票
private int tickets = 100;
//创建锁对象
private Object obj = new Object();
@Override
public void run() {
while (true) {
synchronized (obj) {
if (tickets > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+ "正在出售第" + (tickets--) + "张票");
}
}
}
}
}
2)同步方法:把同步加在方法上
普通方法(同步对象是this)
private synchronized void sellTicket() {
if (tickets > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+ "正在出售第" + (tickets--) + "张票 ");
}
}
public void run() {
while (true) {
if(x%2==0){
synchronized (this) {
if (tickets > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()
+ "正在出售第" + (tickets--) + "张票 ");
}
}
}else {}
静态方法的锁对象是:类的字节码文件对象
private static synchronized void sellTicket() {
if (tickets > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()
+ "正在出售第" + (tickets--) + "张票 ");
}
}
}
public void run() {
while (true) {
if(x%2==0){
synchronized (SellTicket.class) {//这里不可能是this,因为静态中没有this 静态是随着类的加载而加载,首先进内存的是类的字节码文件
if (tickets > 0) {
try {
Thread.sleep(100);
Lock锁
void lock():获取锁。(如果锁不可用,出于线程调度目的,将禁用当前线程,并且在获得锁之前,该线程将一直处于休眠状态。)
void unlock():释放锁
public class SellTicket implements Runnable {
// 定义票
private int tickets = 100;
// 定义锁对象
private Lock lock = new ReentrantLock();
@Override
public void run() {
while (true) {
try {
// 加锁
lock.lock();
if (tickets > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+ "正在出售第" + (tickets--) + "张票");
}
} finally {
// 释放锁
lock.unlock();
}
}
}
}
线程池:(线程池里的每一个线程代码结束后并不会死亡,而是再次回到线程池中成为空闲状态,等待下一个对象来使用)
程序启动一个新线程的成本很高,因为涉及到与操作系统的交互,而使用线程池可以很好的提高性能
JDK5新增了Executors工厂类来产生线程池
方法:
public static ExectorService newCachedThreadPool():开启具有缓存功能的线程池
public static ExectorService newFixedThreadPool(int nThreads):创建指定数量的线程池
public static ExectorService newSingleThreadExector():创建一个
这些方法的返回值是ExectorsService对象,该对象表示一个线程池,可以执行Runnable对象和Callable对象代表的线程
public static void main(String[] args) {
// 创建一个线程池对象,控制要创建几个线程对象。
// public static ExecutorService newFixedThreadPool(int nThreads)
ExecutorService pool = Executors.newFixedThreadPool(2);
// 可以执行Runnable对象或者Callable对象代表的线程
//Future<?> submit(Runnable task): 提交一个 Runnable 任务用于执行,并返回一个表示该任务的 Future。
// <T> Future<T> submit(Callable<T> task): 提交一个返回值的任务用于执行,返回一个表示任务的未决结果Future。
pool.submit(new MyRunnable());
pool.submit(new MyRunnable());
//结束线程池
pool.shutdown();//如果不加结束语句,那么线程执行完毕后重新返回池中,以供其他人使用
}
public class MyRunnable implements Runnable {
@Override
public void run() {
for (int x = 0; x < 100; x++) {
System.out.println(Thread.currentThread().getName() + ":" + x);
}
}
}
定时器:
Timer:(extends Object)一种工具,线程用其安排以后在后台线程中执行的任务。可安排任务执行一次,或者定期重复执行。
Timer()
创建一个新计时器。
schedule(TimerTask task, long delay)
安排在指定延迟后执行指定的任务。
schedule(TimerTask task, long delay, long period)
安排指定的任务从指定的延迟后开始进行重复的固定延迟执行
cancel()
终止此计时器,丢弃所有当前已安排的任务。
TimerTask(extends Objectimplements Runnable)
TimerTask()
创建一个新的计时器任务
run()
此计时器任务要执行的操作。
cancel()
取消此计时器任务。
jvm虚拟机的启动是单线程的还是多线程的?
多线程的。
原因是垃圾回收线程也要先启动,否则很容易会出现内存溢出。
现在的垃圾回收线程加上前面的主线程,最低启动了两个线程,所以,jvm的启动其实是多线程的。
2、设计模式
1)单例设计模式
饿汉式:
懒汉式:(延迟加载)