进程
程序:对数据描述与操作的代码的集合
进程:是程序的一次动态执行过程,它对应了从代码加载、执行至执行完毕的一个完整过程。
进程的特点:
》进程是系统运行程序的基本单位
》每一个进程都有自己独立的一块内存空间、一组系统资源
》每一个进程的内部数据和状态都是完全独立的
进程包括:系统进程、用户进程
线程:
是进程中执行运算的最小单位,可完成一个独立的顺序控制流程。
多线程的好处:
》充分利用CPU资源
》简化编程模型
》带来良好的用户体验
Java中实现多线程
Thread类及其常用方法
》Thread() ---->分配新的Thread对象
》Thread(Runnable target) ---->分配新的Thread对象,target为run()方法被调用的对象
》Thread(Runnable target,String name) ---->分配新的Thread对象,target为run()方法被调用的对象,name为新线程的名字
》void run() ---->执行任务操作的方法
》void start() ---->使该线程开始执行,java虚拟机调用该线程的run()方法
》void sleep(long millis) ---->在指定的毫秒数内让当前正在执行的线程休眠
》String getName() ---->返回线程的名称
》int getPriority() ---->返回线程的优先级
》void setPriority(int newPriority) ---->更改线程的优先级
》static Thread currentThread() ---->返回当前正在执行的线程对象的引用
》boolean isAlive() ---->测试线程是否处于活动状态
》void join() ---->等待该线程终止
》void interrupt() ---->中断线程
》void yield() ---->暂停当前正在执行的线程对象,并执行其他线程
主线程:
在Java程序启动时,一个线程立即运行,该线程通常称为程序的主线程。
重要性:
》它是产生其他子线程的线程
》通常他必须最后完成执行,因为它执行各种关闭操作
主线程的引用通过调用currentThread()方法获得;
示例:
Thread t=Thread.currentThread();
System.out.println("主线程名---更改前---》"+t.getName());
t.setName("gaiming");
System.out.println("主线程名---更改后---》"+t.getName());
使用一个线程的步骤:
》定义一个线程,同时指明这个线程所要执行的代码,即期望完成的功能
》创建线程对象
》启动线程
》终止线程
创建线程类有两种方法:
继承Thread类、实现Runnable接口
区别:
继承Thread类:编写简单,可以直接操作线程,适用于单继承情况
实现Runnable接口:实现多个线程之间资源的共享;适用于多继承情况
》继承Thread类创建线程
示例:
public class DemoThraed extends Thread {
//重写run方法
public void run() {
//输出1~100的整数
for (int i = 1; i <= 100; i++) {
System.out.println("线程名----》"+Thread.currentThread().getName()+",整数---》"+i);//打印线程名和数字
}
}
public static void main(String[] args) {
DemoThraed demo=new DemoThraed();
demo.start();//启动线程,java虚拟机调用该线程的run()方法
}
}
线程实例调用start()和直接调用run()的区别:
调用start()表示该线程处于启动状态,等待操作系统分配资源执行run()方法中的代码,多个线程同时处于启动状态时,线程交替执行。
直接调用run()方法和之前学过的直接调用实例方法没有区别,程序是按顺序执行的,属于单线程执行模式。
示例:start()启动两个线程,交替执行
public class DemoThraed extends Thread {
//重写run方法
public void run() {
//输出1~100的整数
for (int i = 1; i <= 100; i++) {
System.out.println("线程名----》"+Thread.currentThread().getName()+",整数---》"+i);//打印线程名和数字
}
}
public static void main(String[] args) {
DemoThraed demo1=new DemoThraed();
DemoThraed demo2=new DemoThraed();
demo1.start();//启动线程
demo2.start();
}
}
示例:调用run(),顺序执行
public class DemoThraed extends Thread {
//重写run方法
public void run() {
//输出1~100的整数
for (int i = 1; i <= 100; i++) {
System.out.println("线程名----》"+Thread.currentThread().getName()+",整数---》"+i);//打印线程名和数字
}
}
public static void main(String[] args) {
DemoThraed demo1=new DemoThraed();
DemoThraed demo2=new DemoThraed();
demo1.run();//调用方法
demo2.run();
}
}
》实现Runnable接口创建线程
示例:
public class DemoThraed implements Runnable {
// 实现run()方法,
@Override
public void run() {
// 输出1~100的整数
for (int i = 1; i <= 100; i++) {
System.out.println("线程名----》" + Thread.currentThread().getName() + ",整数---》" + i);// 打印线程名和数字
}
}
public static void main(String[] args) {
//实例化DemoThraed对象
DemoThraed demo=new DemoThraed();
//创建Thread对象,并把DemoThraed对象作为参数入参
Thread thread=new Thread(demo);
//调用Thread对象的start()方法启动线程
thread.start();
}
}
线程的状态:
创建、就绪、运行、阻塞、死亡
使线程暂停执行的条件:
》优先级较低
》sleep()方法休眠
》wait()方法等待
》yield()方法让出CPU控制权
》线程由于等待一个文件,I/O事件被阻塞
示例:
public class DemoThraed implements Runnable {
// 实现run()方法,
@Override
public void run() {
System.out.println("线程在运行");
// 输出1~100的整数
for (int i = 1; i <= 100; i++) {
System.out.println("线程名----》" + Thread.currentThread().getName() + ",整数---》" + i);// 打印线程名和数字
try {
Thread.sleep(2000);
System.out.println("2秒后重新运行");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public static void main(String[] args) {
//实例化DemoThraed对象
DemoThraed demo=new DemoThraed();
//创建Thread对象,并把DemoThraed对象作为参数入参
Thread thread=new Thread(demo);
System.out.println("线程为新建");
//调用Thread对象的start()方法启动线程
thread.start();
System.out.println("线程为就绪");
}
}
线程的优先级:(优先级高的线程先执行的概率高)
线程的优先级用1~10表示,1表示优先级最低,10表示优先级最高,默认值为5.
示例:
public class DemoThraed implements Runnable {
// 实现run()方法,
@Override
public void run() {
// 输出1~100的整数
for (int i = 1; i <= 100; i++) {
System.out.println("线程名----》" + Thread.currentThread().getName() + ",整数---》" + i);// 打印线程名和数字
}
}
public static void main(String[] args) {
//实例化DemoThraed对象
DemoThraed demo=new DemoThraed();
//创建Thread对象,并把DemoThraed对象作为参数入参
Thread thread1=new Thread(demo);
Thread thread2=new Thread(demo);
thread1.setPriority(Thread.MAX_PRIORITY);
thread2.setPriority(Thread.MIN_PRIORITY);
//
System.out.println("线程1的优先级"+thread1.getPriority());
System.out.println("线程2的优先级"+thread2.getPriority());
System.out.println("******************************************");
//调用Thread对象的start()方法启动线程
thread1.start();
thread2.start();
}
}
线程的强制运行
join()方法使当前线程暂停执行,等待调用该方法的线程结束后再继续执行本线程。
线程的礼让:
yield()方法可暂停当前线程执行,允许其他具有相同优先级的线程获得运行机会,该线程处于就绪状态,不转为阻塞状态。若无其他相同或更高优先级的线程,则该线程继续执行。
线程同步的实现:
当两个或多个线程需要访问同一资源时,需要以某种顺序来确保该资源某一时刻只能被一个线程使用,这就称为线程同步。
有两种方式:同步方法、同步代码块
》同步方法
使用synchronized修饰方法
示例:
public class Site implements Runnable{
private int count=10;//记录剩余票数
private int number=0;//记录买到第几张
private boolean flag=false;//记录是否售完
@Override
public void run() {
while(!flag) {
sale();
}
}
//售票方法
synchronized public void sale() {
if (count<=0) {
flag=true;
return;
}
//1.修改数据
number++;
count--;
try {
Thread.sleep(500);//模拟网络延迟
} catch (Exception e) {
// TODO: handle exception
}
//显示信息
System.out.println(Thread.currentThread().getName()+"抢到第"+number+"张票,"+"剩余"+count+"张票");
}
public static void main(String[] args) {
Site site=new Site();
Thread thread1=new Thread(site);
Thread thread2=new Thread(site);
Thread thread3=new Thread(site);
thread1.setName("逃泡泡");
thread2.setName("黄牛");
thread3.setName("代理");
thread2.setPriority(7);
thread3.setPriority(8);
thread1.start();
thread2.start();
thread3.start();
}
}
》同步代码块
使用synchronized修饰的代码块
语法:
synchronized(){
//需要同步的代码
}
优点:可以针对任意代码块,可以任意指定上锁的对象,因此灵活性更高
示例:
public class Site implements Runnable {
private int count = 10;// 记录剩余票数
private int number = 0;// 记录买到第几张
private boolean flag = false;// 记录是否售完
@Override
public void run() {
while (!flag) {
synchronized (this) {
if (count <= 0) {
flag = true;
return;
}
// 1.修改数据
number++;
count--;
try {
Thread.sleep(500);// 模拟网络延迟
} catch (Exception e) {
// TODO: handle exception
}
// 显示信息
System.out.println(Thread.currentThread().getName() + "抢到第" + number + "张票," + "剩余" + count + "张票");
}
}
}
public static void main(String[] args) {
Site site = new Site();
Thread thread1 = new Thread(site);
Thread thread2 = new Thread(site);
Thread thread3 = new Thread(site);
thread1.setName("逃泡泡");
thread2.setName("黄牛");
thread3.setName("代理");
thread2.setPriority(7);
thread3.setPriority(8);
thread1.start();
thread2.start();
thread3.start();
}
}
-----------------------------
线程安全的类型
一个类在被多个线程访问时,不管运行环境执行这些线程有什么样的时序安排,他必须以固定的、一致的顺序执行。这样的类型称为线程安全的类型。
Hashtable和HashMap
》继承关系不同
两者都实现了Map接口,Hashtable继承了Dictionary类,HashMap继承了AbstractMap类
》是否线程安全
Hashtable是线程安全的,其中的方法是同步的
HashMap中的方法在默认情况下是非同步的
》是否允许出现null值
Hashtable中的键和值都不允许为null
HashMap中,null可以作为键也可以作为值
》效率比较
HashMap重速度,轻安全。