进程
线程
线程的调度
主线程
public class Therad01 {
public static void main(String[] args) {
//1.创建一个Thread类的子类
class MyThread extends Thread {
//在Thread类的子类中重写Thread类中的run方法
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println("run:" + i);
}
}
}
//3创建Thread类的子类对象
MyThread mt = new MyThread();
//4.调用Thread类中的方法start方法,开启新的线程,执行run方法
mt.start();
//主线程会继续执行主方法中的代码
for (int i=0;i<20;i++){
System.out.println("run:"+i);
}
}
}
public class Thread02
{
public static void main(String[] args) {
//定义子类的对象
Mythread02 my = new Mythread02();
//调用start()方法启动线程
my.start();
new Mythread02().start();
new Mythread02().start();
new Mythread02().start();
}
import javax.print.DocFlavor;
/*
获取线程的名称:
1.使用Thread类中的方法getName()
String getName()返回线程的名称
2.可以先获取到当前正在执行的线程,使用线程中的方法getName()获取线程的名称
static Thread currentThread()返回当前正在执行的线程对象的引用
*/
//定义一个Thread类的子类
public class Mythread02 extends Thread
{
//重写Thread类子类中的run()方法
@Override
public void run() {
//获取线程名称
//String name = getName();
//System.out.println(name);
Thread t = Thread.currentThread();
System.out.println(t);
String name = t.getName();
System.out.println(name);
//链式编程
System.out.println(Thread.currentThread().getName());
}
}
/*
设置线程的名称:(了解)
1.使用Thread类中的setName(名字)
void setName(String name)改变线程名称,使之与参数name相同
2.创建一个带参数的构造方法,参数传递线程名称,调用父类的带参构造方法,把线程名称传递给父类,让父类(Thread)给子线程起一个名字
Thread(String name)分配新的Thread对象
*/
public class Mythread extends Thread{
public Mythread(){
}
public Mythread (String name){
super(name);//把线程名称传递给父类,让父类(Thread)给子线程起一个名字
}//super可用于在子类构造方法中调用父类的构造方法
@Override
public void run() {
//获取线程名称
System.out.println(Thread.currentThread().getName());
}
}
public class dome01 {
public static void main(String[] args) {
//开启多线程
Mythread mt=new Mythread();
mt.setName("小王");
mt.start();
//开启多线程
new Mythread("小李").start();
}
}
/*
public static void sleep(long millis):使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行)
毫秒结束后,线程继续执行
*/
public class Deom {
public static void main(String[] args) {
//模拟秒表
for (int i=1; i<= 60; i++) {
System.out.println(i);
//使用Thread类中的sleep方法让程序睡眠1秒钟
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Runable接口
/创建一个Runnable接口的实现类
public class Runnable01 implements Runnable{
//在实现类中重写Runnable接口的run方法,设置线程任务
@Override
public void run() {
for (int i=0;i<10;i++){
System.out.println(Thread.currentThread().getName()+"-->"+i);
}
}
}
/*
实现步骤
1.创建一个Runnable接口的实现类
2.在实现类中重写Runnable接口的run方法,设置线程任务
3.创建一个Runnable接口的实现类对象
4.创建Thread类对象,构造方法中传递Runnable接口的实现类对象
5.调用Thread类中的start方法,开启新的线程执行run方法
实现Runnable接口创建多线程程序的好处
1.避免了单继承的局限性
一个类只能继承一个类(一个人只能有一个亲爹),类继承了Thread类就不能继承其他的类
实现了Runable接口,还可以继承其他的类,实现其他的接口
2.增强了程序的扩展性,降低了程序的耦合性(解耦)
实现Runable接口的方式,把设置线程任务和开启新的线程进行了分离
实现类中,重写了run方法,用来设置线程任务
创建Thread类对象,调用start方法,用来开启新线程
*/
public class Demo {
public static void main(String[] args) {
//3.创建一个Runnable接口的实现类对象
Runnable01 run = new Runnable01();
//4.创建Thread类对象,构造方法中传递Runnable接口的实现类对象
Thread t = new Thread(run);
//5.调用Thread类中的start方法,开启新的线程执行run方法
t.start();
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + "-->" + i);
//返回对当前正在执行的线程对象的引用currentThread
}
}
}
匿名内部类与线程
/
匿名内部类方式实现线程的创建
匿名:没有名字
内部类:写在其他类内部的类
匿名内部类的作用:简化代码
把子类继承父类,重写父类的方法,创建子类对象合成一步完成
把实现类实现类接口,重写接口中的方法,创建实现类对像合成一步完成
匿名内部类的最终产物:子类/实现类对象,而这个类没有名字
格式:
new父类/接口(){
重复父类、接口中的方法
}
*/
public class NiMing{
public static void main(String[] args) {
//线程的父类是Thread
//new MyThread().start();
new Thread() {
//重写run方法,设置线程任务
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName() + "-->" + "黑马");
}
}
}.start();
//线程的接口Runanble
//Runnable r=new Runnable01();//多态
Runnable r= new Runnable() {
@Override
//重写run方法,设置线程任务
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName() + "-->" + "程序员");
}
}
};
new Thread®.start();
//简化接口的方式
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName() + "-->" + "搬运工");
}
}
}).start();
}
}*
线程安全概述
****
**卖票案例代码实现
*/
卖票案例 有问题
*/
public class Runnable02 implements Runnable
{
private int ticket=100;
@Override
public void run() {
//判断是否有票
while (true){
if (ticket>0){
System.out.println(Thread.currentThread().getName()+"正在卖第"+ticket+"张票");
ticket--;
}
}
}
}
public class MaiPiao
{
public static void main(String[] args) {
Runnable02 r =new Runnable02();
Thread t0 =new Thread(r);
Thread t1=new Thread(r);
Thread t2=new Thread(r);
t0.start();
t1.start();
t2.start();
}
}
卖票问题解决代码
/*
卖票案例
卖票案例出现了线程安全问题
卖出了不存在的票和重复的票
解决线程安全问题的一种方案;使用同步代码块
格式 :
synchronized (锁对象){
可能会出现线程安全问题的代码(访问了共享数据的代码)
}
注意:1.通过代码块中的锁对象,可以使用任意的对象
2.但是必须保证多个线程使用的锁对象是同一个
3.锁对象作用:
把同步代码块锁住,只让一个线程在同步代码块中执行
*/
public class Runnable02 implements Runnable {
//定义票
private int ticket = 100;
//创建一个锁对象
Object obj = new Object();
@Override
public void run() {
//判断是否有票
//使用死循环,让卖票操作重复执行
while (true) {
//同步代码块
synchronized (obj) {
if (ticket > 0) {
//提高安全问题出现的概率,让程序睡眠
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在卖第" + ticket + "张票");
ticket--;
}
}
}
}
}
public class MaiPiao {
public static void main(String[] args) {
Runnable02 r =new Runnable02();
Thread t0 =new Thread(r);
Thread t1=new Thread(r);
Thread t2=new Thread(r);
t0.start();
t1.start();
t2.start();
}
}
同步代码块原理
同步方法
/*
卖票案例
卖票案例出现了线程安全问题
卖出了不存在的票和重复的票
解决线程安全问题的二种方案;使用同步方法
使用步骤:1.把访问共享数据的代码抽取出来,放到一个方法中
2.在方法上添加synchronized修饰符
格式:定义方法的格式
修饰符 synchronized 返回值类型 方法名(参数列表){
可能会出现线程安全问题的代码(访问了共享数据的代码)
}
*/
public class Runnable02 implements Runnable {
//定义票
private int ticket = 100;
//创建一个锁对象
Object obj = new Object();
@Override
public void run() {
System.out.println("this"+this);
//使用死循环,让卖票操作重复执行
while (true) {
//同步代码块
payTicke();
}
}
/*
定义一个同步方法
同步方法也会把方法内部的代码锁住
只让一个线程执行
同步方法的锁对象是谁?
就是实现类对象 new Runnable02()
也就是this
*/
public synchronized void payTicke(){
if (ticket > 0) {
//提高安全问题出现的概率,让程序睡眠
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在卖第" + ticket + "张票");
ticket--;
}
}
}
public class MaiPiao {
public static void main(String[] args) {
Runnable02 r =new Runnable02();
System.out.println("r"+ r);
Thread t0 =new Thread(r);
Thread t1=new Thread(r);
Thread t2=new Thread(r);
t0.start();
t1.start();
t2.start();
}
}
Lock锁
/*
卖票案例
卖票案例出现了线程安全问题
卖出了不存在的票和重复的票
解决线程安全问题的三种方案;使用Lock锁
java.util.concurrent.Locks.Lock接口
Lock实现提供了比使用synchronized方法和语句可获得的更广泛的锁定操作
Lock接口中的方法:
void Lock()获取锁
void unLock()释放锁
java.util.concurrent.Locks.ReentranrLock implements Lock接口
使用步骤:
1.在成员位置创建一个ReentranrLock对象
2.在可能会出现安全问题的代码前调用Lock接口中的方法Lock获取锁
3.在可能会出现安全问题的代码前调用Lock接口中的方法unLock释放锁
*/
public class Runnable02 implements Runnable {
//定义票
private int ticket = 100;
//1.在成员位置创建一个ReentranrLock对象
Lock l = new ReentrantLock();
public void run() {
System.out.println("this" + this);
//使用死循环,让卖票操作重复执行
while (true) {
l.lock();
if (ticket > 0) {
//提高安全问题出现的概率,让程序睡眠
try {
Thread.sleep(10);
System.out.println(Thread.currentThread().getName() + "正在卖第" + ticket + "张票");
ticket--;
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
// 3.在可能会出现安全问题的代码前调用Lock接口中的方法unLock释放锁
l.unlock();//无论程序是否异常,都会把锁释放掉
}
}
}
}
/* @Override
public void run() {
System.out.println("this" + this);
//使用死循环,让卖票操作重复执行
while (true) {
l.lock();
if (ticket > 0) {
//提高安全问题出现的概率,让程序睡眠
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在卖第" + ticket + "张票");
ticket--;
}
// 3.在可能会出现安全问题的代码前调用Lock接口中的方法unLock释放锁
l.unlock();
}
}
*/
}
public class MaiPiao {
public static void main(String[] args) {
Runnable02 r =new Runnable02();
System.out.println("r"+ r);
Thread t0 =new Thread(r);
Thread t1=new Thread(r);
Thread t2=new Thread(r);
t0.start();
t1.start();
t2.start();
}
}