线程
进程:进程是系统分配资源调用的一个独立单位.
多进程的意义:1>目前计算机就是一种多进程,在做一件事情的同时还可以做另一件事情.2>多进程是为了提高计算机CPU的使用率.
单线程:程序的执行路劲只有一条.
多线程:程序的执行路劲有多条.特点:具有随机性!
多线程程序实现方式1:
1)自定一个类:MyThread 继承自Thread类
2)在MyThread类中重写Thread类中的run() .
3)在主线程中,创建该类的实例对象,启动线程
获取线程的名称:
public final String getName()返回该线程的名称.
设置线程名称:
public final void setName(String name)改变线程名称,使之与参数 name 相同.
其他方法:
public final void join()throws InterruptedException等待该线程终止.
public final int getPriority()返回线程的优先级.优先级大的抢占到CPU的执行权大,并不代表就一定能抢到,因为线程的执行具有随机性!
public static void yield()暂停当前正在执行的线程对象,并执行其他线程.暂停当前线程执行其他线程,并不保证另一个线程就一定能抢占到CPU的执行权.
public final void setDaemon(boolean on) :on指定true,就是设置守护线程.jvm自动退出,对于主线程的数据如果直接输出完毕,对于两个守护线程来说不会立即消失,Jvm等会就
动退出.
public static void sleep(long millis)throws InterruptedException在指定的毫秒数内让当前正在执行的线程休眠(暂停执行).
线程停止:public final void stop():强迫线程停止执行.方法过时.
public void interrupt()中断线程.表示中断线程一种状态
相关代码:
public class ThreadDemo {
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.start();
try {
Thread.sleep(3000);
Thread.interrupted();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
import java.util.Date;
public class MyThread extends Thread{
@Override
public void run() {
System.out.println("开始执行:"+new Date());
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
System.out.println("线程终止");
}
System.out.println("结束执行:"+new Date());
}
}
多线程实现的第二种方式:
开发步骤:
1)自定义一个类MyRunnable,该类实现Runnable接口.
2)实现该接口中的run()方法.
3)在主线程中创建该类的实例对象,
4)创建Thread类对象,将3)创建的这个对象作为参数进行传递.
5)分别启动线程.
相关代码:
public class MyRunnable implements Runnable{
@Override
public void run() {
for(int i=0;i<100;i++){
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
public class RunnableDemo2 {
public static void main(String[] args) {
MyRunnable my = new MyRunnable() ;
Thread t1 = new Thread(my, "立华奏") ;
Thread t2 = new Thread(my, "小薰") ;
t1.start() ;
t2.start() ;
}
}
检验多线程安全问题的标准(以后在判断一个多线程序是否有安全问题的标准)
1)当前是否是一个多线程环境.
2)多线程环境中是否有共享数据.
3)是否有多条语句对共享数据进行操作.
同步锁定对象:
1)可以Object类型以及任意的Java类型对象
2)如果一个方法进来之后是一个同步代码块,那么同步代码块可以演变成一个同步方法
3)如果是一个静态的同步方法,锁对象是当前类名class属性:类名.class (反射机制:获取一些类的字节码文件对象Class类对象)
例题:某电影院目前正在上映贺岁大片(红高粱,少林寺传奇藏经阁),共有100张票,而它有3个售票窗口售票,请设计一个程序模拟该电影院售票.
相关代码:
public class SellTicket implements Runnable {
//100张票公用
private static int ticket=100;
//同步锁对象
private Object obj=new Object();
//任一类的对象
private Demo d=new Demo();
private int x;
@Override
public void run() {
while(true){
if(x%2==0){
synchronized (SellTicket.class) {//静态同步方法
if(ticket>0){
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()
+ "正在出售第" + (ticket--) + "张票");
}
}
}else{
sellTikcket();
}
x++;
}
}
private static synchronized void sellTikcket() {
if(ticket>0){
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在出售第"
+ (ticket--) + "张票");
}
}
}
class Demo{
}
public class RunnableDemo {
public static void main(String[] args) {
SellTicket sellticket= new SellTicket();
Thread thread = new Thread(sellticket,"窗口1");
Thread thread2 = new Thread(sellticket, "窗口2");
Thread thread3 = new Thread(sellticket, "窗口3");
thread.start();
thread2.start();
thread3.start();
}
}
使用同步机制的这种方式解决线程安全问题,但是不知道具体的锁对象在哪里添加,以及在哪里释放.JDK5提供了一个更具体的锁对象:Lock.
Lock 实现提供了比使用 synchronized 方法和语句可获得的更广泛的锁定操作.
Lock是一个接口,用ReentrantLock子类来实现.
public void lock():获取锁.
public void unlock():试图释放此锁.
相关代码:
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class SellTicket2 implements Runnable{
private static int ticket=100;
private Lock lock=new ReentrantLock();
@Override
public void run() {
while(true){
try{
lock.lock();
if(ticket>0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()
+ "正在出售第" + (ticket--) + "张票");
}
}finally{
lock.unlock();
}
}
}
}
同步机制的弊端:1>效率低(每一个线程在抢占到CPU的执行权,会将门关闭,别的线程进不来),2>容易出现死锁.
死锁线程:两个或者两个以上的线程出现了互相等待的情况,就会出现死锁!
面试题:
wait()线程等待,notify(),唤醒单个线程,notifyAll():唤醒所有线程这三个方法为什么不定义到Thread类中呢,而是定义在Object类中?
线程中会存在安全问题,并且解决线程安全问题使用的同步代码块或者同步方法来解决,同步代码块来解决线程安全问题,就存在同步锁对象,谁能代表同步锁对象(Object以及任
的Java类),把它定义到Object类中.
线程组:表示一个线程的集合:Java允许一个线程中有多个线程.
设置线程组名称:
public ThreadGroup(String name):构造一个新的线程组.
Thread类有个构造方法:将创建的线程组对象当参数带入
public Thread(ThreadGroup group,Runnable target,String name){ }
获取线程组对象:
public final ThreadGroup getThreadGroup():返回该线程的线程组.
多线程程序的实现方式3:(很少用到)
线程池:JDK5新增了一个Executors工厂类来产生线程池.
好处:节约成本,很多线程用完不会立即被垃圾处理器处理掉,而是回收到线程池中被利用.
方法:public static ExecutorsService newFixedThreadPool(int nThreads):参数直接指定线程池中有多少个线程.
其返回值是ExecutorsService对象,该对象表示一个线程池.可以执行Runnable或者Callable对象代表的线程.
ExecutorsService接口的方法:Future<?>submit(Runnable task);<T>Future<T>submit<Callable<T> task>返回值:异步计算的结果!
相关代码:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ExecutorsDemo {
public static void main(String[] args) {
ExecutorService pool=Executors.newFixedThreadPool(2);
pool.submit(new MyRunnable());
pool.submit(new MyRunnable());
pool.shutdown();
}
}
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class CallableDemo {
public static void main(String[] args) throws InterruptedException, ExecutionException {
ExecutorService ThreadPool=Executors.newFixedThreadPool(2);
Future<Integer> submit = ThreadPool.submit(new MyCallable());
Future<Integer> submit2 = ThreadPool.submit(new MyCallable());
Integer i1=submit.get();
Integer i2=submit2.get();
System.out.println(i1);
System.out.println(i2);
}
}
多线程中匿名内部类的方式.
格式:new 类名(具体类,抽象类) ,接口(){重写方法}
相关代码:
public class ThreadDemo2 {
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
for(int i=0;i<100;i++){
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}).start();
}
}
定时器:Timer:
常用的几个方法:
public void schedule(TimerTask task,Date time):安排在指定的时间执行指定的任务.
public void schedule(TimerTask task,long delay):在多少毫秒后执行指定任务.
public void schedule(TimerTask task,long delay,long period):在多少毫秒后,执行任务,并且每个多少毫秒重新执行
public void cancel():终止此计时器,丢弃所有当前已安排的任务.