线程
一、什么是线程?什么是进程?
现在我们使用的计算机基本上都是多任务的操作系统,一个线程实现一个任务,而这多任务就是靠多条线程实现的。在java中,main()方法运行就一个
主线程。
进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程中可以启动多个线程。
二、线程的启动方法:
使用java.lang.Thread类或者java.lang.Runnable接口编写代码来实例化和启动新线程。
1.方法一、继承Thread类:
a.子类覆盖父类中的run()方法,将线程运行的代码放在run()方法中。
b.建立子类对象的同时,线程也被创建。
c.在调用start()方法,启动线程。
代码举例:
2.方法二、继承Runnable接口:
a.子类覆盖接口中的run方法。
b.通过Thread类创建线程,并将实现了Runnable接口的子类对象作为参数传递给Thread类的构造函数。
c.Thread类对象调用start方法开启线程。
代码举例:
注意:直接调用run方法无法启动线程。
三、关于线程几个重要方法:
sleep():可以让当前线程挂起一个指定的时间段。这是一种让进程的其他线程得到处理器时间的一个有效手段;该方法有着两种重载形式:以毫秒为单位指定睡
眠时间和以纳秒为单位指定睡眠时间。
join():将会使得一个线程等待另外一个线程执行结束。假如现在A线程正在执行,这时调用B.jion(),A线程会等B线程执行完后执行。
yield():让出cpu,让其他线程和自己这个线程一起抢这个时间段,有可能执行的还是自己。
isAlive():线程是否还在运行.
getPriority():获取当前线程优先级
setPriority():线程优先级设置,值在10-1之间。
四、线程的同步
多线程的同步依靠的是对象锁机制,synchronized关键字的背后就是利用了封锁来实现对共享资源的互斥访问。
synchronized关键字:
第一点:synchronized用来标识一个普通方法时,表示一个线程要执行该方法,必须取得该方法所在的对象的锁。
第二点:synchronized用来标识一个静态方法时,表示一个线程要执行该方法,必须获得该方法所在的类的类锁。
第三点:synchronized修饰一个代码块。类似这样:synchronized(obj) { //code.... }。表示一个线程要执行该代码块,必须获得obj的锁。这样
做的目的是减小锁的粒度,保证当不同块所需的锁不冲突时不用对整个对象加锁。利用零长度的byte数组对象做obj非常经济。
一个例子,该例子模仿多人存取同一个账户:
Account类:
/**
* 注意wait的用法,必须在loop中,必须在拥有锁的代码块中。 前者是当被notify的时候要重新进行条件判断,后者是为了释放锁。
User类:
1 wait方法:
该方法属于Object的方法,wait方法的作用是使得当前调用wait方法所在部分(代码块)的线程停止执行,并释放当前获得的调用wait所在的代码块的
锁,并在其他线程调用notify或者notifyAll方法时恢复到竞争锁状态(一旦获得锁就恢复执行)。
调用wait方法需要注意几点:
第一点:wait被调用的时候必须在拥有锁(即synchronized修饰的)的代码块中。
第二点:恢复执行后,从wait的下一条语句开始执行,因而wait方法总是应当在while循环中调用,以免出现恢复执行后继续执行的条件不满足却继续
执行的情况。
第三点:若wait方法参数中带时间,则除了notify和notifyAll被调用能激活处于wait状态(等待状态)的线程进入锁竞争外,在其他线程中
interrupt它或者参数时间到了之后,该线程也将被激活到竞争状态。
第四点:wait方法被调用的线程必须获得之前执行到wait时释放掉的锁重新获得才能够恢复执行。
2 notify方法和notifyAll方法:
notify方法通知调用了wait方法,但是尚未激活的一个线程进入线程调度队列(即进入锁竞争),注意不是立即执行。并且具体是哪一个线程不能保证
。另外一点就是被唤醒的这个线程一定是在等待wait所释放的锁。
notifyAll方法则唤醒所有调用了wait方法,尚未激活的进程进入竞争队列。
一、什么是线程?什么是进程?
现在我们使用的计算机基本上都是多任务的操作系统,一个线程实现一个任务,而这多任务就是靠多条线程实现的。在java中,main()方法运行就一个
主线程。
进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程中可以启动多个线程。
二、线程的启动方法:
使用java.lang.Thread类或者java.lang.Runnable接口编写代码来实例化和启动新线程。
1.方法一、继承Thread类:
a.子类覆盖父类中的run()方法,将线程运行的代码放在run()方法中。
b.建立子类对象的同时,线程也被创建。
c.在调用start()方法,启动线程。
代码举例:
public class ThreadTest extends Thread{
//线程名字
String threadname;
//构造器
public ThreadTest(String name){
threadname=name;
}
/**
* 重写run放法,打印1-100之间的数
*/
@Override
public void run(){
for(int i=1;i<100;i++){
System.out.println(threadname+"线程正在启动:"+i);
}
}
public static void main(String[] args) {
//创建对象
ThreadTest test1=new ThreadTest("test1");
//
ThreadTest test2=new ThreadTest("test2");
//启动线程
test1.start();
test2.start();
}
}
2.方法二、继承Runnable接口:
a.子类覆盖接口中的run方法。
b.通过Thread类创建线程,并将实现了Runnable接口的子类对象作为参数传递给Thread类的构造函数。
c.Thread类对象调用start方法开启线程。
代码举例:
public class RunTest implements Runnable {
@Override
public void run(){
for(int i=0;i<1000;i++){
System.out.println(i);
}
}
public static void main(String[] args) {
//创建对象
RunTest runTest=new RunTest();
//创建线程对象
Thread thread1=new Thread(runTest);
Thread thread2=new Thread(runTest);
//启动线程,这里启动是两个线程
thread1.start();
thread2.start();
}
}
注意:直接调用run方法无法启动线程。
三、关于线程几个重要方法:
sleep():可以让当前线程挂起一个指定的时间段。这是一种让进程的其他线程得到处理器时间的一个有效手段;该方法有着两种重载形式:以毫秒为单位指定睡
眠时间和以纳秒为单位指定睡眠时间。
join():将会使得一个线程等待另外一个线程执行结束。假如现在A线程正在执行,这时调用B.jion(),A线程会等B线程执行完后执行。
yield():让出cpu,让其他线程和自己这个线程一起抢这个时间段,有可能执行的还是自己。
isAlive():线程是否还在运行.
getPriority():获取当前线程优先级
setPriority():线程优先级设置,值在10-1之间。
四、线程的同步
多线程的同步依靠的是对象锁机制,synchronized关键字的背后就是利用了封锁来实现对共享资源的互斥访问。
synchronized关键字:
第一点:synchronized用来标识一个普通方法时,表示一个线程要执行该方法,必须取得该方法所在的对象的锁。
第二点:synchronized用来标识一个静态方法时,表示一个线程要执行该方法,必须获得该方法所在的类的类锁。
第三点:synchronized修饰一个代码块。类似这样:synchronized(obj) { //code.... }。表示一个线程要执行该代码块,必须获得obj的锁。这样
做的目的是减小锁的粒度,保证当不同块所需的锁不冲突时不用对整个对象加锁。利用零长度的byte数组对象做obj非常经济。
一个例子,该例子模仿多人存取同一个账户:
Account类:
package com.synchronize;
import java.util.HashMap;
import java.util.Iterator;
public class Account {
private static HashMap<String, Integer> m = new HashMap<String, Integer>();
private static long times = 0;
static {
m.put("ren", 1000);
}
public synchronized void save(String name, int num) {
long tempTime = times++;
System.out.println("第 " + tempTime + " 次存储" + num + "之前" + name + "的余额为:" + m.get(name));
m.put(name, m.get(name) + num);
this.notify();
System.out.println("第 " + tempTime + " 次存储" + num + "之后" + name + "的余额为:" + m.get(name));
}
public static int get(String name) {
return m.get(name);
}
/**
* 注意wait的用法,必须在loop中,必须在拥有锁的代码块中。 前者是当被notify的时候要重新进行条件判断,后者是为了释放锁。
*
* @param name
* @param num
*/
public synchronized void load(String name, int num) {
long tempTime = times++;
System.out.println("第 " + tempTime + " 次提取" + num + "之前" + name + "的余额为:" + m.get(name));
try {
while (m.get(name) < num) {
System.out.println("第 " + tempTime + " 次提取" + "余额" + m.get(name) + "不足,开始等待wait。");
this.wait();
System.out.println("第 " + tempTime + " 次提取操作被唤醒");
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
m.put(name, m.get(name) - num);
System.out.println("第 " + tempTime + " 次提取" + num + "之后" + name + "的余额为:" + m.get(name));
}
}
User类:
package com.synchronize;
/**
* 这里注意runnable接口的线程是怎么实例化的。new Thread(new User())
* 这里成功展示了多个用户存取同一个账户的多线程实例,通过多线程同步,保证了安全的执行。
* @author abc
*
*/
public class User implements Runnable {
private static Account account = new Account();
private final int id;
User(int i){
id=i;
}
public void run() {
int tempMoney = 100;
account.load("ren", tempMoney);
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
account.save("ren", 100);
System.out.println("线程"+id+"完毕========================================================");
}
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(new User(i)).start();
}
}
}
1 wait方法:
该方法属于Object的方法,wait方法的作用是使得当前调用wait方法所在部分(代码块)的线程停止执行,并释放当前获得的调用wait所在的代码块的
锁,并在其他线程调用notify或者notifyAll方法时恢复到竞争锁状态(一旦获得锁就恢复执行)。
调用wait方法需要注意几点:
第一点:wait被调用的时候必须在拥有锁(即synchronized修饰的)的代码块中。
第二点:恢复执行后,从wait的下一条语句开始执行,因而wait方法总是应当在while循环中调用,以免出现恢复执行后继续执行的条件不满足却继续
执行的情况。
第三点:若wait方法参数中带时间,则除了notify和notifyAll被调用能激活处于wait状态(等待状态)的线程进入锁竞争外,在其他线程中
interrupt它或者参数时间到了之后,该线程也将被激活到竞争状态。
第四点:wait方法被调用的线程必须获得之前执行到wait时释放掉的锁重新获得才能够恢复执行。
2 notify方法和notifyAll方法:
notify方法通知调用了wait方法,但是尚未激活的一个线程进入线程调度队列(即进入锁竞争),注意不是立即执行。并且具体是哪一个线程不能保证
。另外一点就是被唤醒的这个线程一定是在等待wait所释放的锁。
notifyAll方法则唤醒所有调用了wait方法,尚未激活的进程进入竞争队列。