进程与线程
进程
系统运行程序的基本单位
有独立的内存空间和系统资源
线程
进程中执行运算的最小单位
处理机分配给线程,即真正在处理机上运行的是线程
线程
创建线程的两种传统方式
继承Thread类
MyThread thread = new MyThread();
thread.start();//启动线程
实现Runnable接口
MyRunnable runnable = new MyRunnable();
new Thread(runnable).start();
API
Thread 线程类
getName()
获得当前线程的名称
currentThread()
获得当前线程
sleep()
让线程的睡眠指定的时间
多线程会提高程序的运行效率吗?
不会,性能会降低。
为什么多线程下载会速度快?
其实是在抢服务器的带宽。
创建定时器
定时器
1.Timer类与TimerTask类
//5秒钟后调度执行任务
//只执行一次
//相同一个定时器只能用一次,否则会报错
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
//任务
}
}, 5*1000);
//5秒钟后调度执行任务,以后每2秒再执行一次
Timer timer = new Timer();
//5秒钟后调度任务
timer.schedule(new TimerTask() {
@Override
public void run() {
//任务
}
}, 5*1000,2*1000);
线程同步synchronized
1.同步代码块
synchronized (this) {
}
2.同步方法
public synchronized void output(){}
锁对象是当前Java类的字节码对象 Test.class
线程通信-wait/notify
生产者与消费者
Lock&Condition
Lock比传统线程模型中的synchronized方式更加面向对象,与生活中的锁类似。
锁本身也应该是一个对象。两个线程执行的代码片段要实现同步互斥的效果,他们必须
用同一个Lock对象,锁是代表要操作的资源的类的内部方法中,而不是线程线程代码中。
线程范围内的共享数据
//有问题,打印的数据不对
public class ThreadShareData1 {
private static int data = 0;
static class A{
public void get(){
System.out.println(Thread.currentThread().getName()+" a:"+data);
}
}
static class B{
public void get(){
System.out.println(Thread.currentThread().getName()+" b:"+data);
}
}
public static void main(String[] args) {
for(int i = 0;i<5;i++){
new Thread(new Runnable() {
@Override
public void run() {
data = new Random().nextInt(100);
System.out.println(Thread.currentThread().getName()+" input data :"+data);
new A().get();
new B().get();
}
}).start();
}
}
}
//在某一个线程内,有独立的数据
public class ThreadShareData {
private static Map<Thread,Integer> threadData = new HashMap<Thread,Integer>();
static class A{
public void get(){
int data = threadData.get(Thread.currentThread());
System.out.println(Thread.currentThread().getName()+" a:"+data);
}
}
static class B{
public void get(){
int data = threadData.get(Thread.currentThread());
System.out.println(Thread.currentThread().getName()+" b:"+data);
}
}
public static void main(String[] args) {
for(int i = 0;i<5;i++){
new Thread(new Runnable() {
@Override
public void run() {
int data = new Random().nextInt(100);
System.out.println(Thread.currentThread().getName()+" input data :"+data);
threadData.put(Thread.currentThread(), data);
new A().get();
new B().get();
}
}).start();
}
}
}
//Java提供的类,解决线程数据共享问题
//在某一个线程内,有独立的数据
//总结:一个ThreadLocal只能代表一个变量,所以其中只能放一个数据。如果你有两个变量,只能创建两个ThreadLocal对象。
//也可以把一堆数据封装到一个对象中。
public class ThreadShareData {
//相当于往map中放整数
private static ThreadLocal<Integer> tl = new ThreadLocal<Integer>();
static class A{
public void get(){
int data = tl.get();
System.out.println(Thread.currentThread().getName()+" a:"+data);
}
}
static class B{
public void get(){
int data = tl.get();
System.out.println(Thread.currentThread().getName()+" b:"+data);
}
}
public static void main(String[] args) {
for(int i = 0;i<5;i++){
new Thread(new Runnable() {
@Override
public void run() {
int data = new Random().nextInt(100);
System.out.println(Thread.currentThread().getName()+" input data :"+data);
tl.set(data);
new A().get();
new B().get();
}
}).start();
}
}
}
//在某一个线程内,有独立的数据,封装多个数据
class User{
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class ThreadShareData {
//相当于往map中放整数
private static ThreadLocal<User> tl = new ThreadLocal<User>();
static class A{
public void get(){
User user = tl.get();
System.out.println(Thread.currentThread().getName()+" a:"+user.getName());
}
}
static class B{
public void get(){
User user = tl.get();
System.out.println(Thread.currentThread().getName()+" b:"+user.getName());
}
}
public static void main(String[] args) {
for(int i = 0;i<2;i++){
new Thread(new Runnable() {
@Override
public void run() {
int data = new Random().nextInt(100);
System.out.println(Thread.currentThread().getName()+" input data :"+data);
User user = new User();
user.setId(data);
user.setName("user"+data);
tl.set(user);
new A().get();
new B().get();
}
}).start();
}
}
}
优美设计
public class Data {
private Data(){}
/**
* 每个线程调用全局的ThreadLocal对象的set方法,就相当于往其内部的map对象中添加一条记录。
* key分别是各自的线程,value是传入的值。
* 在线程结束的时候可以调用ThreadLocal的clear方法,这样可以快速释放内存。不调用也可以,在线程结束的时候自动释放。
* */
private static ThreadLocal<Data> map = new ThreadLocal<Data>();
public static Data getInstance(){//这里不需要synchronized
Data data = map.get();
if(data == null){
data = new Data();
map.set(data);
}
return data;
}
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class ThreadShareData {
//相当于往map中放整数
static class A{
public void get(){
System.out.println(Thread.currentThread().getName()+" a:"+Data.getInstance().getId());
}
}
static class B{
public void get(){
System.out.println(Thread.currentThread().getName()+" b:"+Data.getInstance().getId());
}
}
public static void main(String[] args) {
for(int i = 0;i<2;i++){
new Thread(new Runnable() {
@Override
public void run() {
int data = new Random().nextInt(100);
System.out.println(Thread.currentThread().getName()+" input data :"+data);
Data.getInstance().setId(data);
new A().get();
new B().get();
}
}).start();
}
}
}
多个线程访问共享对象和数据的方式
可以使用同一个Runnable对象,这样就可以操作同一个数据了