Java API —— 多线程(2)

1、JDK5中Lock锁的使用
  虽然我们可以理解同步代码块和同步方法的锁对象问题,但是我们并没有直接看到在哪里加上了锁,在哪里释放了锁,为了更清晰的表达如何加锁和释放锁,JDK5以后提供了一个新的锁对象Lock。
  · Lock
    void lock()
    void unlock()
  · ReentrantLock
自定义类:

package cn.itcast01;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
 * Created by gao on 16-1-6.
 */
public class SellTicket implements Runnable {
    private int tickets = 100;
    // 定义锁对象
    private Lock lock = new ReentrantLock();
    @Override
    public void run() {
        while (true) {
            //加锁
            try {
                lock.lock();
                if (tickets > 0) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "---" + (tickets--) + "张票");
                }
            } finally {
                //释放锁
                lock.unlock();
            }
        }
    }
}

测试类:

package cn.itcast01;
/**
 * Created by gao on 16-1-6.
 */
/*
 * 虽然我们可以理解同步代码块和同步方法的锁对象问题,但是我们并没有直接看到在哪里加上了锁,在哪里释放了锁,
 * 为了更清晰的表达如何加锁和释放锁,JDK5以后提供了一个新的锁对象Lock。
 *
 * Lock:
 *         void lock(): 获取锁。
 *         void unlock():释放锁。
 * ReentrantLock是Lock的实现类.
 */
public class SellTicketDemo {
    public static void main(String[] args) {
        SellTicket s = new SellTicket();
        Thread t1 = new Thread(s,"窗口1");
        Thread t2 = new Thread(s,"窗口2");
        Thread t3 = new Thread(s,"窗口3");
        t1.start();
        t2.start();
        t3.start();
    }
}

2、死锁问题

1)同步弊端

· 效率低

· 如果出现了同步嵌套,就容易产生死锁问题

2)死锁问题及其代码

· 是指两个或者两个以上的线程在执行的过程中,因争夺资源产生的一种互相等待现象

· 同步代码块的嵌套案例

自定义线程类:

package cn.itcast_02;
public class DieLock extends Thread {
    private boolean flag;
    public DieLock(boolean flag) {
        this.flag = flag;
    }
    @Override
    public void run() {
        if (flag) {
            synchronized (MyLock.objA) {
                System.out.println("if objA");
                synchronized (MyLock.objB) {
                    System.out.println("if objB");
                }
            }
        } else {
            synchronized (MyLock.objB) {
                System.out.println("else objB");
                synchronized (MyLock.objA) {
                    System.out.println("else objA");
                }
            }
        }
    }
}

自定义锁:

package cn.itcast_02;
public class MyLock {
    // 创建两把锁对象
    public static final Object objA = new Object();
    public static final Object objB = new Object();
}

测试类:

package cn.itcast_02;
/*
 * 同步的弊端:
 *         A:效率低
 *         B:容易产生死锁
 *
 * 死锁:
 *         两个或两个以上的线程在争夺资源的过程中,发生的一种相互等待的现象。
 *
 * 举例:
 *         中国人,美国人吃饭案例。
 *         正常情况:
 *             中国人:筷子两支
 *             美国人:刀和叉
 *         现在:
 *             中国人:筷子1支,刀一把
 *             美国人:筷子1支,叉一把
 */
public class DieLockDemo {
    public static void main(String[] args) {
        DieLock dl1 = new DieLock(true);
        DieLock dl2 = new DieLock(false);
        dl1.start();
        dl2.start();
    }
}

3、线程间通信

1)通过设置线程(生产者)和获取线程(消费者)针对同一个学生对象进行操作

例子1:

学生类:

package cn.itcast_04;
public class Student {
    String name;
    int age;
}

设置线程类:

package cn.itcast_04;
public class SetThread implements Runnable {
    private Student s;
    private int x = 0;
    public SetThread(Student s) {
        this.s = s;
    }
    @Override
    public void run() {
        while (true) {
            synchronized (s) {
                if (x % 2 == 0) {
                    s.name = "林青霞";//刚走到这里,就被别人抢到了执行权
                    s.age = 27;
                } else {
                    s.name = "刘意"; //刚走到这里,就被别人抢到了执行权
                    s.age = 30;
                }
                x++;
            }
        }
    }
}

获取线程类:

package cn.itcast_04;
public class GetThread implements Runnable {
    private Student s;
    public GetThread(Student s) {
        this.s = s;
    }
    @Override
    public void run() {
        while (true) {
            synchronized (s) {
                System.out.println(s.name + "---" + s.age);
            }
        }
    }
}

测试类:

package cn.itcast_04;
/*
 * 分析:
 *         资源类:Student
 *         设置学生数据:SetThread(生产者)
 *         获取学生数据:GetThread(消费者)
 *         测试类:StudentDemo
 *
 * 问题1:按照思路写代码,发现数据每次都是:null---0
 * 原因:我们在每个线程中都创建了新的资源,而我们要求的时候设置和获取线程的资源应该是同一个
 * 如何实现呢?
 *         在外界把这个数据创建出来,通过构造方法传递给其他的类。
 *
 * 问题2:为了数据的效果好一些,我加入了循环和判断,给出不同的值,这个时候产生了新的问题
 *         A:同一个数据出现多次
 *         B:姓名和年龄不匹配
 * 原因:
 *         A:同一个数据出现多次
 *             CPU的一点点时间片的执行权,就足够你执行很多次。
 *         B:姓名和年龄不匹配
 *             线程运行的随机性
 * 线程安全问题:
 *         A:是否是多线程环境        是
 *         B:是否有共享数据        是
 *         C:是否有多条语句操作共享数据    是
 * 解决方案:
 *         加锁。
 *         注意:
 *             A:不同种类的线程都要加锁。
 *             B:不同种类的线程加的锁必须是同一把。
 */
public class StudentDemo {
    public static void main(String[] args) {
        //创建资源
        Student s = new Student();

        //设置和获取的类
        SetThread st = new SetThread(s);
        GetThread gt = new GetThread(s);
        //线程类
        Thread t1 = new Thread(st);
        Thread t2 = new Thread(gt);
        //启动线程
        t1.start();
        t2.start();
    }
}

  

  2)等待唤醒机制

例子1:

学生类:

package cn.itcast05;
/**
 * Created by gao on 16-1-6.
 */
public class Student {
    String name;
    int age;
    boolean flag; // 默认情况是没有数据,如果是true,说明有数据
}

设置线程类:

package cn.itcast05;
/**
 * Created by gao on 16-1-6.
 */
public class SetThread implements Runnable {
    private Student s;
    private int x = 0;
    public SetThread(Student s) {
        this.s = s;
    }
    @Override
    public void run() {
        while (true) {
            synchronized (s) {
                //判断有没有
                if (s.flag) {
                    try {
                        s.wait();  //t1等着,释放锁
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                if (x % 2 == 0){
                    s.name = "林青霞";
                    s.age = 27;
                }else{
                    s.name = "刘意";
                    s.age = 30;
                }
                x++;
                //修改标记
                s.flag = true;
                //唤醒线程
                s.notify(); //唤醒t2,唤醒并不表示你立马可以执行,必须还得抢CPU的执行权。
            }
            //t1有,或者t2有
        }
    }
}

获取线程类:

package cn.itcast05;
/**
 * Created by gao on 16-1-6.
 */
public class GetThread implements Runnable {
    private Student s;
    public GetThread(Student s) {
        this.s = s;
    }
    @Override
    public void run() {
        while (true) {
            synchronized (s) {
                if (!s.flag) {
                    try {
                        s.wait(); //t2就等待了。立即释放锁。将来醒过来的时候,是从这里醒过来的时候
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println(s.name + "---" + s.age);
                //修改标记
                s.flag = false;
                //唤醒线程
                s.notify(); //唤醒t1
            }
        }
    }
}

测试类:

package cn.itcast05;
/**
 * Created by gao on 16-1-6.
 */
/* 等待唤醒:
* Object类中提供了三个方法:
* wait():等待
* notify():唤醒单个线程
* notifyAll():唤醒所有线程
* 为什么这些方法不定义在Thread类中呢?
* 这些方法的调用必须通过锁对象调用,而我们刚才使用的锁对象是任意锁对象。
* 所以,这些方法必须定义在Object类中。
*/
public class StudentDemo {
    public static void main(String[] args) {
        //创建资源
        Student s = new Student();
        //设置和获取的类
        SetThread st = new SetThread(s);
        GetThread gt = new GetThread(s);
        //线程类
        Thread t1 = new Thread(st);
        Thread t2 = new Thread(gt);
        //启动线程
        t1.start();
        t2.start();
    }
}

例子2(优化):

学生类:

package cn.itcast_07;
public class Student {
    private String name;
    private int age;
    private boolean flag; // 默认情况是没有数据,如果是true,说明有数据
    public synchronized void set(String name, int age) {
        // 如果有数据,就等待
        if (this.flag) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        // 设置数据
        this.name = name;
        this.age = age;
        // 修改标记
        this.flag = true;
        this.notify();
    }
    public synchronized void get() {
        // 如果没有数据,就等待
        if (!this.flag) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        // 获取数据
        System.out.println(this.name + "---" + this.age);
        // 修改标记
        this.flag = false;
        this.notify();
    }
}

设置线程类:

package cn.itcast_07;
public class SetThread implements Runnable {
    private Student s;
    private int x = 0;
    public SetThread(Student s) {
        this.s = s;
    }
    @Override
    public void run() {
        while (true) {
            if (x % 2 == 0) {
                s.set("林青霞", 27);
            } else {
                s.set("刘意", 30);
            }
            x++;
        }
    }
}

获取线程类:

package cn.itcast_07;
public class GetThread implements Runnable {
    private Student s;
    public GetThread(Student s) {
        this.s = s;
    }
    @Override
    public void run() {
        while (true) {
            s.get();
        }
    }
}

测试类:

package cn.itcast_07;
/*
 * 最终版代码中:
 *         把Student的成员变量给私有的了。
 *         把设置和获取的操作给封装成了功能,并加了同步。
 *         设置或者获取的线程里面只需要调用方法即可。
 */
public class StudentDemo {
    public static void main(String[] args) {
        //创建资源
        Student s = new Student();

        //设置和获取的类
        SetThread st = new SetThread(s);
        GetThread gt = new GetThread(s);
        //线程类
        Thread t1 = new Thread(st);
        Thread t2 = new Thread(gt);
        //启动线程
        t1.start();
        t2.start();
    }
}

4、线程的状态转换图

5、线程组

· Java中使用ThreadGroup来表示线程组,它可以对一批线程进行分类管理,Java允许程序直接对线程组进行控制。

· 默认情况下,所有的线程都属于主线程组。

public final ThreadGroup getThreadGroup()

· 我们也可以给线程设置分组

Thread(ThreadGroup group, Runnable target, String name)

自定义线程类:

package cn.itcast06;
public class MyRunnable implements Runnable {
    @Override
    public void run() {
        for (int x = 0; x < 100; x++) {
            System.out.println(Thread.currentThread().getName() + ":" + x);
        }
    }
}

测试类:

package cn.itcast06;
/*
 * 线程组: 把多个线程组合到一起。
 * 它可以对一批线程进行分类管理,Java允许程序直接对线程组进行控制。
 */
public class ThreadGroupDemo {
    public static void main(String[] args) {
        // method1();
        // 我们如何修改线程所在的组呢?
        // 创建一个线程组
        // 创建其他线程的时候,把其他线程的组指定为我们自己新建线程组
        method2();
        // t1.start();
        // t2.start();
    }
    private static void method2() {
        // ThreadGroup(String name)
        ThreadGroup tg = new ThreadGroup("这是一个新的组");
        MyRunnable my = new MyRunnable();
        // Thread(ThreadGroup group, Runnable target, String name)
        Thread t1 = new Thread(tg, my, "林青霞");
        Thread t2 = new Thread(tg, my, "刘意");

        System.out.println(t1.getThreadGroup().getName());
        System.out.println(t2.getThreadGroup().getName());

        //通过组名称设置后台线程,表示该组的线程都是后台线程
        tg.setDaemon(true);
    }
    private static void method1() {
        MyRunnable my = new MyRunnable();
        Thread t1 = new Thread(my, "林青霞");
        Thread t2 = new Thread(my, "刘意");
        // 我不知道他们属于那个线程组,我想知道,怎么办
        // 线程类里面的方法:public final ThreadGroup getThreadGroup()
        ThreadGroup tg1 = t1.getThreadGroup();
        ThreadGroup tg2 = t2.getThreadGroup();
        // 线程组里面的方法:public final String getName()
        String name1 = tg1.getName();
        String name2 = tg2.getName();
        System.out.println(name1);
        System.out.println(name2);
        // 通过结果我们知道了:线程默认情况下属于main线程组
        // 通过下面的测试,你应该能够看到,默任情况下,所有的线程都属于同一个组
        System.out.println(Thread.currentThread().getThreadGroup().getName());
    }
}

6、线程池

1)

2)在JDK5之前,我们必须手动实现自己的线程池,从JDK5开始,Java内置支持线程池。

3)JDK5新增了一个Executors工厂类来产生线程池,有如下几个方法:

· public static ExecutorService newCachedThreadPool()

· public static ExecutorService newFixedThreadPool(int nThreads)

· public static ExecutorService newSingleThreadExecutor()

· 这些方法的返回值是ExecutorService对象,该对象表示一个线程池,可以执行Runnable对象或者Callable对象代表的线程。它提供了如下方法:

· Future<?> submit(Runnable task)

· <T> Future<T> submit(Callable<T> task)

4)案例演示

· 创建线程池对象

· 创建Runnable实例

· 提交Runnable实例

· 关闭线程池

例子1:

自定义线程类:

package cn.itcast_08;
public class MyRunnable implements Runnable {
    @Override
    public void run() {
        for (int x = 0; x < 100; x++) {
            System.out.println(Thread.currentThread().getName() + ":" + x);
        }
    }
}

测试类:

package cn.itcast_08;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ExecutorsDemo {
    public static void main(String[] args) {
        // 创建一个线程池对象,控制要创建几个线程对象。
        // public static ExecutorService newFixedThreadPool(int nThreads)
        ExecutorService pool = Executors.newFixedThreadPool(2);
        // 可以执行Runnable对象或者Callable对象代表的线程
        pool.submit(new MyRunnable());
        pool.submit(new MyRunnable());
        //结束线程池
        pool.shutdown();
    }
}

例子2:

自定义线程类:

package cn.itcast_09;
import java.util.concurrent.Callable;
//Callable:是带泛型的接口。
//这里指定的泛型其实是call()方法的返回值类型。
public class MyCallable implements Callable {
    @Override
    public Object call() throws Exception {
        for (int x = 0; x < 100; x++) {
            System.out.println(Thread.currentThread().getName() + ":" + x);
        }
        return null;
    }
}

测试类:

package cn.itcast_09;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CallableDemo {
    public static void main(String[] args) {
        //创建线程池对象
        ExecutorService pool = Executors.newFixedThreadPool(2);

        //可以执行Runnable对象或者Callable对象代表的线程
        pool.submit(new MyCallable());
        pool.submit(new MyCallable());

        //结束
        pool.shutdown();
    }
}

例子3:线程求和

自定义线程类:

package cn.itcast10;
import java.util.concurrent.Callable;
/**
 * Created by gao on 16-1-7.
 */
public class MyCallable implements Callable<Integer> {
    private int number;
    public MyCallable(int number) {
        this.number = number;
    }
    @Override
    public Integer call() throws Exception {
        int sum = 0;
        for (int x = 1; x <= number; x++) {
            sum += x;
        }
        return sum;
    }
}

测试类:

package cn.itcast10;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class CallableDemo {
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        // 创建线程池对象
        ExecutorService pool = Executors.newFixedThreadPool(2);
        // 可以执行Runnable对象或者Callable对象代表的线程
        Future<Integer> f1 = pool.submit(new MyCallable(100));
        Future<Integer> f2 = pool.submit(new MyCallable(200));
        // V get()
        Integer i1 = f1.get();
        Integer i2 = f2.get();
        System.out.println(i1);
        System.out.println(i2);
        // 结束
        pool.shutdown();
    }
}

7、匿名内部类方式使用多线程

  · new Thread(){代码…}.start();
  · new Thread(new Runnable(){代码…}).start();

package cn.itcast10;
/**
 * Created by gao on 16-1-7.
 */
/*
 * 匿名内部类的格式:
 *         new 类名或者接口名() {
 *             重写方法;
 *         };
 *         本质:是该类或者接口的子类对象。
 */
public class ThreadDemo01 {
    public static void main(String[] args) {
        // 继承Thread类来实现多线程
        new Thread(){
            public void run(){
                for(int x = 0; x < 100; x++){
                    System.out.println(Thread.currentThread().getName()+"---"+":"+x);
                }
            }
        }.start();
        // 实现Runnable接口来实现多线程
        new Thread(new Runnable() {
            @Override
            public void run() {
                for(int x = 0; x < 100; x++){
                    System.out.println(Thread.currentThread().getName()+"---"+":"+x);
                }
            }
        }).start();
        // 更有难度的
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int x = 0; x < 100; x++) {
                    System.out.println("hello" + ":" + x);
                }
            }
        }) {
            public void run() {
                for (int x = 0; x < 100; x++) {
                    System.out.println("world" + ":" + x);
                }
            }
        }.start();
    }
}

8、定时器
  1)定时器是一个应用十分广泛的线程工具,可用于调度多个定时任务以后台线程的方式执行。在Java中,可以通过Timer和TimerTask类来实现定义调度的功能
  2)Timer
    · public Timer()
    · public void schedule(TimerTask task, long delay)
    · public void schedule(TimerTask task,long delay,long period)
  3)TimerTask
    · public abstract void run()
    · public boolean cancel()
  4)开发中
    · Quartz是一个完全由java编写的开源调度框架。
例子1:

package cn.itcast_12;
import java.util.Timer;
import java.util.TimerTask;
/*
 * 定时器:可以让我们在指定的时间做某件事情,还可以重复的做某件事情。
 * 依赖Timer和TimerTask这两个类:
 * Timer:定时
 *         public Timer()
 *         public void schedule(TimerTask task,long delay)
 *         public void schedule(TimerTask task,long delay,long period)
 *         public void cancel()
 * TimerTask:任务
 */
public class TimerDemo {
    public static void main(String[] args) {
        // 创建定时器对象
        Timer t = new Timer();
        // 3秒后执行爆炸任务
        // t.schedule(new MyTask(), 3000);
        //结束任务
        t.schedule(new MyTask(t), 3000);
    }
}
// 做一个任务
class MyTask extends TimerTask {
    private Timer t;

    public MyTask(){}

    public MyTask(Timer t){
        this.t = t;
    }

    @Override
    public void run() {
        System.out.println("beng,爆炸了");
        t.cancel();
    }
}

例子2:

package cn.itcast_12;
import java.util.Timer;
import java.util.TimerTask;
public class TimerDemo2 {
    public static void main(String[] args) {
        // 创建定时器对象
        Timer t = new Timer();
        // 3秒后执行爆炸任务第一次,如果不成功,每隔2秒再继续炸
        t.schedule(new MyTask2(), 3000, 2000);
    }
}
// 做一个任务
class MyTask2 extends TimerTask {
    @Override
    public void run() {
        System.out.println("beng,爆炸了");
    }
}

例子3:

package cn.itcast_12;
import java.io.File;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
/*
 * 需求:在指定的时间删除我们的指定目录(你可以指定c盘,但是我不建议,我使用项目路径下的demo)
 */
class DeleteFolder extends TimerTask {
    @Override
    public void run() {
        File srcFolder = new File("demo");
        deleteFolder(srcFolder);
    }
    // 递归删除目录
    public void deleteFolder(File srcFolder) {
        File[] fileArray = srcFolder.listFiles();
        if (fileArray != null) {
            for (File file : fileArray) {
                if (file.isDirectory()) {
                    deleteFolder(file);
                } else {
                    System.out.println(file.getName() + ":" + file.delete());
                }
            }
            System.out.println(srcFolder.getName() + ":" + srcFolder.delete());
        }
    }
}
public class TimerTest {
    public static void main(String[] args) throws ParseException {
        Timer t = new Timer();
        String s = "2014-11-27 15:45:00";
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date d = sdf.parse(s);
        t.schedule(new DeleteFolder(), d);
    }
}

多线程常见面试题

1)多线程有几种实现方案,分别是哪几种?

  两种。继承Thread类和实现Runnable接口。扩展一种:实现Callable接口。这个得和线程池结合。

2)同步有几种方式,分别是什么?

  两种。同步代码块同步方法

3)启动一个线程是run()还是start()?它们的区别?

  启动一个线程是start()。run():封装了被线程执行的代码,直接调用仅仅是普通方法的调用。start():启动线程,并由JVM自动调用run()方法。

4)sleep()和wait()方法的区别

  sleep():必须指时间;不释放锁。wait():可以不指定时间,也可以指定时间;释放锁。

5)为什么wait(),notify(),notifyAll()等方法都定义在Object类中

  因为这些方法的调用是依赖于锁对象的,而同步代码块的锁对象是任意锁。而Object代码任意的对象,所以,定义在这里面。

6)线程的生命周期图

  新建 -- 就绪 -- 运行 -- 死亡

  新建 -- 就绪 -- 运行 -- 阻塞 -- 就绪 -- 运行 -- 死亡

时间: 2024-11-03 21:49:04

Java API —— 多线程(2)的相关文章

Java API —— 多线程

1.多线程概述     1)进程: 正在运行的程序,是系统进行资源分配和调用的独立单位. 每一个进程都有它自己的内存空间和系统资源.     2)线程: 在同一个进程内又可以执行多个任务,而这每一个任务我就可以看出是一个线程. 线程:是程序的执行单元,执行路径.是程序使用CPU的最基本单位. 单线程:程序只有一条执行路径. 多线程:程序有多条执行路径.     3)多线程有什么意义? 多线程的存在,不是提高程序的执行速度.其实是为了提高应用程序的使用率. 程序的执行其实都是在抢CPU的资源,CP

HBase Java API使用(一)

前言 1. 创建表:(由master完成) 首先需要获取master地址(master启动时会将地址告诉zookeeper)因而客户端首先会访问zookeeper获取master的地址 client和master通信,然后有master来创建表(包括表的列簇,是否cache,设置存储的最大版本数,是否压缩等). 2. 读写删除数据 client与regionserver通信,读写.删除数据 写入和删除数据时讲数据打上不同的标志append,真正的数据删除操作在compact时发生 3. 版本信息

HBase Java API使用

概括 1. 创建.删除及启用禁用表.添加列等都需用到HBaseAdmin,另外需要注意删除,添加列等操作都需要禁用表 2. 表中添加数据,查询等都是和HTable相关,如果是多线程的情况下注意用HTablePool 3.  插入数据使用Put,可以单行添加也可批量添加 4. 查询数据需使用Get,Result,Scan.ResultScanner等 一.HBaseConfiguration org.apache.hadoop.hbase.HBaseConfiguration 对HBase进行配置

Hbase框架原理及相关的知识点理解、Hbase访问MapReduce、Hbase访问Java API、Hbase shell及Hbase性能优化总结

转自:http://blog.csdn.net/zhongwen7710/article/details/39577431 本blog的内容包含: 第一部分:Hbase框架原理理解 第二部分:Hbase调用MapReduce函数使用理解 第三部分:Hbase调用Java API使用理解 第四部分:Hbase Shell操作 第五部分:Hbase建表.读写操作方式性能优化总结 第一部分:Hbase框架原理理解 概述 HBase是一个构建在HDFS上的分布式列存储系统:HBase是基于Google

Java基础——多线程(1)

进程:应用程序在内存中分配的空间(正在运行的程序). 线程:是进程中负责程序执行的执行单元,也称为执行路径. 一个进程中至少有一个线程,在负责该进程的运行. 如果一个进程中出现了多个线程,就称为该程序为多线程程序. 多线程技术:解决多部分代码同时执行的需求,合理使用CPU资源. 多线程的运行是根据CPU的切换完成的,怎么切换是CPU说的算.所多线程运行有一个随机性(CPU快速切换造成的). jvm中的多线程: 至少有两个线程,一个是负责自定义代码运行的,一个是负责垃圾回收的. 发现结果并不相同,

JAVA进阶-多线程(3)

1.以前使用线程API并没有返回结果,Callable/Future/FutureTask正是解决了此问题,并在调用过程中 作出对异常的捕获 -Callable执行call()方法返回Object对象,也可抛出异常;调用 Callable并不像Thread,而是调用<T> Future ExecutorService.submit(Callable<T> task); -Future 返回值,调用该接口的get()方法,可返回对应的对象 ------------------ Sal

Java 中多线程

很多核心Java面试题来源于多线程(Multi-Threading)和集合框架(Collections Framework),理解核心线程概念时,娴熟的实际经验是必需的.这篇文章收集了 Java 线程方面一些典型的问题,这些问题经常被高级工程师所问到. 0.Java 中多线程同步是什么? 在多线程程序下,同步能控制对共享资源的访问.如果没有同步,当一个 Java 线程在修改一个共享变量时,另外一个线程正在使用或者更新同一个变量,这样容易导致程序出现错误的结果. 1.解释实现多线程的几种方法? 一

二、java实现多线程的方式?

一.同步?异步? 下面两幅图解释了同步异步. 二.实现多线程的方式 1.继承Thread package threaddemo; class CreateThreadDemo extends Thread{ /** * 线程执行的任务,执行的代码 */ @Override public void run() { for (int i = 0; i <30 ; i++) { System.out.println("我是线程:"+i+ "名字:"+Thread.c

笔记:MyBatis 使用 Java API配置

我们已经讨论了各种MyBatis配置元素,如envronments.typeAlias和typeHandlers,以及如何使用XML配置它们.即使你想使用基于JavaAPI的MyBatis配置,MyBatis的SqlSessionFactory接口除了使用基于XML的配置创建外也可以通过Java API 编程式地被创建.每个在XML中配置的元素,都可以编程式的创建.使用Java API创建SqlSessionFactory,代码如下: ? ? ????public?static?SqlSessi