多线程学习
创建线程的方式
创建线程的方法一
继承Thread类,重写run()方法,调用start开启线程
public class TestThread01 extends Thread{
@Override
public void run() {
// run方法线程体
for (int i = 0; i < 20; i++) {
System.out.println("我在看代码"+i);
}
}
public static void main(String[] args) {
// main线程体 , 主线程
// 创建一个线程对象
TestThread01 tt = new TestThread01();
// 调用start()方法开启线程
tt.start();
for (int i = 0; i < 20; i++) {
System.out.println("我在学习"+i);
}
}
创建线程的方法二
实现Runnable接口,重写run()方法,执行线程需要丢入runable接口实现类,调用start方法。
public class TestThread03 implements Runnable{
@Override
public void run() {
// run方法线程体
for (int i = 0; i < 20; i++) {
System.out.println("我在看代码"+i);
}
}
public static void main(String[] args) {
// 创建runnable接口的实现类对象
TestThread03 tt3 = new TestThread03();
// 创建线程对象,通过线程对象来开启我们的线程(代理)
// Thread thread = new Thread(tt3);
// thread.start();
new Thread(tt3).start();
for (int i = 0; i < 20; i++) {
System.out.println("我在学习"+i);
}
}
创建线程的方法三
实现callable接口,callable的好处,可以定义返回值,可以抛出异常。
public class TestCallable implements Callable<Boolean> {
private String url;// 网络图片的地址
private String name;// 保存文件的文件名
public TestCallable(String url,String name){
this.url= url;
this.name= name;
}
// 下载图片线程的执行体
@Override
public Boolean call(){
WebDownLoader wdl = new WebDownLoader();
wdl.downlocader(url,name);
System.out.println("下载的文件名为:"+name);
return true;
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
TestCallable tt2= new TestCallable("url","2.jpg");
TestCallable tt3= new TestCallable("url","3.jpg");
TestCallable tt4= new TestCallable("url","4.jpg");
// 创建执行服务
ExecutorService es = Executors.newFixedThreadPool(3);
// 提交执行
Future<Boolean> r1= es.submit(tt2);
Future<Boolean> r2= es.submit(tt3);
Future<Boolean> r3= es.submit(tt4);
// 获取结果
boolean rs1 = r1.get();
boolean rs2 = r2.get();
boolean rs3 = r3.get();
// 关闭服务
es.shutdownNow();
}
}
// 下载器
class WebDownLoader{
// 下载方法
public void downlocader(String url,String name){
try {
FileUtils.copyURLToFile(new URL(url),new File(name));
} catch (IOException e) {
e.printStackTrace();
System.out.println("IO异常,downlocader方法出现问题");
}
}
静态代理
静态代理模式:真实对象和代理对象都实现同一个接口。代理对象要代理真实角色;好处在于代理对象可以做很多真实对象做不了的事情,真实对象可以专注于做自己的事情
public class StaticProxy {
public static void main(String[] args) {
WeddingCompany wc= new WeddingCompany(new You());
wc.HappyMarry();
}
}
interface Marry{
void HappyMarry();
}
class You implements Marry{
@Override
public void HappyMarry() {
System.out.println("结婚很开心");
}
}
// 代理角色,帮助你结婚
class WeddingCompany implements Marry{
private Marry target;
public WeddingCompany(Marry target){
this.target =target;
}
@Override
public void HappyMarry() {
before();
this.target.HappyMarry();
after();
}
private void before(){
System.out.println("结婚之前布置现场");
}
private void after(){
System.out.println("结婚之后结尾款");
}
}
Lambda表达式
推导lambda表达式
public class TestLambda01 {
// 3.静态内部类
static class Like2 implements ILike {
@Override
public void Lambda() {
System.out.println(" i like lambda2");
}
}
public static void main(String[] args) {
ILike like = new Like();
like.Lambda();
like= new Like2();
like.Lambda();
// 4.局部内部类
class Like3 implements ILike {
@Override
public void Lambda() {
System.out.println(" i like lambda3");
}
}
like = new Like3();
like.Lambda();
// 5.匿名内部类,没有类的名称,必须借助接口或者父类
like = new ILike() {
@Override
public void Lambda() {
System.out.println(" i like lambda4");
}
};
like.Lambda();
// 6.用Lambda简化
like = ()-> {
System.out.println(" i like lambda5");
};
like.Lambda();
}
}
// 1.定义一个函数式接口
interface ILike{
void Lambda();
}
// 2.实现类
class Like implements ILike {
@Override
public void Lambda() {
System.out.println(" i like lambda");
}
}
最终结果
// 最终 lambda表达式
public class TestLambda03 {
public static void main(String[] args) {
Test test= null;
test = (a,b)->{
System.out.println("乌拉乌拉"+a);
System.out.println("乌拉乌拉"+b);
};
test.test("jie","wan");
}
}
interface Test{
void test(String a ,String b);
}
join方法(插队)和延时方法
/ 测试join方法 插队
public class TestJoin implements Runnable{
@Override
public void run() {
for (int i = 0; i < 200; i++) {
System.out.println("vip来了"+i);
}
}
public static void main(String[] args) throws InterruptedException {
// 启动线程
TestJoin tj= new TestJoin();
Thread thread = new Thread(tj);
thread.start();
// 主线程
for (int i = 0; i < 1000; i++) {
if (i==300){
thread.join();//插队
}
System.out.println("main"+i);
}
}
利用延时模拟倒计时
public static void tenDown() throws InterruptedException {
int num = 10;
while (true){
Thread.sleep(1000);
System.out.println(num--);
if (num<=0){
break;
}
}
}
stop方法和Yield方法
public class TestStop implements Runnable {
// 1. 设置一个标志位
private boolean flag =true;
@Override
public void run() {
int i = 0;
while (flag){
System.out.println("rum.....Thread"+i++);
}
}
// 2.设置一个公开的方法停止线程,转换标志位
public void stop(){
this.flag = false;
}
public static void main(String[] args) {
TestStop ts= new TestStop();
new Thread(ts).start();
for (int i = 0; i < 1000; i++) {
System.out.println("main"+i);
if(i==900){
// 调用stop方法切换标志位,让线程停止
ts.stop();
System.out.println("停止");
}
// 测试礼让线程
// 礼让不一定成功,看CPU心情
public class TestYield {
public static void main(String[] args) {
MyYield myYield = new MyYield();
new Thread(myYield,"3").start();
new Thread(myYield,"4").start();
new Thread(myYield,"5").start();
new Thread(myYield,"6").start();
}
}
class MyYield implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"开始");
Thread.yield();
System.out.println(Thread.currentThread().getName()+"结束");
}
Yield:礼让不一定成功,看CPU心情
线程锁
线程锁:主要用来给方法、代码块加锁。当某个方法或者代码块使用锁时,那么在同一时刻至多仅有有一个线程在执行该段代码。当有多个线程访问同一对象的加锁方法/代码块时,同一时间只有一个线程在执行,其余线程必须要等待当前线程执行完之后才能执行该代码段。但是,其余线程是可以访问该对象中的非加锁代码块的。
public class TestLock {
public static void main(String[] args) {
TestLock2 tl2= new TestLock2();
new Thread(tl2).start();
new Thread(tl2).start();
new Thread(tl2).start();
}
}
class TestLock2 implements Runnable{
int ticketNums= 10;
// 定义lock锁
private final ReentrantLock lock = new ReentrantLock();
@Override
public void run() {
while (true){
try {
lock.lock();// 加锁
if (ticketNums>0){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(ticketNums--);
}
}finally {
// 解锁
lock.unlock();
}
}
}
}
生产者消费者模型
管程法:利用缓冲区来实现。
class SynContainer{
// 需要一个容器大小
Chicken[] chickens =new Chicken[10];
// 容器计数器
int counts = 0;
// 生产者放入产品
public synchronized void push(Chicken chicken){
//如果容器满了,就需要等待消费者消费
if (counts==chickens.length){
//通知消费者消费,生产者等待
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//如果没有满,生产者就需要生产产品放入
chickens[counts]=chicken;
counts++;
// 通知消费者消费
this.notifyAll();
}
// 消费者消费产品
public synchronized Chicken pop(){
if (counts==0){
//等待生产者生产,消费者等待
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 如果可以消费
counts--;
Chicken chicken = chickens[counts];
// 吃完了等待生产者生产
this.notifyAll();
return chicken;
}
信号灯法:标志位解决。
lass TV{
// 演员表演,观众等待
// 观众观看,演员等待
String voice;//表演的节目
boolean flag =true;
// 表演
public synchronized void play(String voice){
if (!flag){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("演员表演了:"+voice);
// 通知观众观看
this.notifyAll();// 通知唤醒
this.voice = voice;
this.flag = !this.flag;
}
// 观看
public synchronized void watch() {
if (flag){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("观看了:"+voice);
// 通知演员表演
this.notifyAll();
this.flag = !this.flag;
}
线程池
public class TestPool {
public static void main(String[] args) {
// 1.创建服务,创建线程池
// newFixedThreadPool 参数为:线程池大小
ExecutorService service = Executors.newFixedThreadPool(10);
// 执行
service.execute(new MyThread());
service.execute(new MyThread());
service.execute(new MyThread());
service.execute(new MyThread());
service.execute(new MyThread());
// 2. 关闭连接
service.shutdown();
}
}
class MyThread implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}