Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
FateFree
Nov 14, 2003

geeves posted:

Also Java's own documentation follows this model as well. https://docs.oracle.com/javase/tutorial/jdbc/basics/prepared.html

That java example requires the scope change because they are using the variable in the catch/finally clause. If you need to do that, you are forced to declare it outside. His example was not however, so it shouldn't be done. Why would you do that for the PreparedStatement and not for the String that creates the query? Or any variable for that sense? You should only move things out of scope when its required.

Zaphod42 posted:

Why do you have to continue to talk down to me dismissively like I've never heard of improving code readability? Everything I've posted in this thread suggests I know exactly what you're talking about. Where we disagree is over how big a deal this is to readability; not whether readability matters period. Very arrogant attitude.

Because

Zaphod42 posted:

Saving a line doesn't matter. Who cares.

It sounds like you don't care about code readability, or you wouldn't have said this was a waste of time when the entire purpose of it was to improve code readability! I just can't give someone credit about code readability when they openly dismiss something that improves code readability. I literally see no advantage to just 'leaving it because who cares' other than laziness.

Adbot
ADBOT LOVES YOU

denzelcurrypower
Jan 28, 2011
Thanks for the help, everyone. After changing the table name and ensuring I include the properly encoded ' symbols, it works OK now. Just in time for me to run into a new error.

I'm working on a Java web application, and when I attempt to reference jQuery / Bootstrap in the head, the styles doesn't seem to be applied to my page. E.g:

code:

<%@ page contentType="text/html; charset=UTF-8" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

<html>
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags --> 
    <title>Home page</title>
    
    <!-- jQuery -->
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
    <!-- Bootstrap JavaScript files -->
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
    <!-- Bootstrap CSS files --> 
    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
    <!-- Custom CSS themes -->
    <link href="<c:url value="/resources/main.css"/>" rel="stylesheet"> 
    
</head>
<body>
    <h2>Home Page</h2>
    <div class="has-success">${msg}</div>
    
    <h3>This is the home page!</h3>
</body>
</html>
Do I need to do something special in this case for Bootstrap styles to be applied?

venutolo
Jun 4, 2003

Dinosaur Gum
At my job, we recently had a bug in a production application and I'm interested for ideas as to how we can attempt to prevent this in the future. Here's some example code to illustrate the bug:

code:
public class SomeDao {

    private JdbcTemplate jdbcTemplate;

    public SomeDao(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    void addRange(Range range) {
        // here is the bug - second parameter should be range.getEnd()
        jdbcTemplate.update("call some_proc(?, ?)", range.getStart(), range.getStart());
    }

}
The developer never put it in for code review and I have no idea how QA didn't catch that the wrong end values were being written to the database. For the purposes of my question, let's assume that the code was reviewed but this small defect was missed. And let's assume that I want to catch this before it even goes to QA. So what sort of (automated) process might catch this thing?

We are not terribly sophisticated when it comes to automated testing. I write unit tests that provide good coverage for my code, but I'm kind of in the middle of the totem pole and don't set the culture/standards/expectations. So as a whole we really, really lack in unit testing and way too much of our code is not covered by any automated tests. That being said, I'm not sure how you would unit test this, or even if that is appropriate. Previously, I've used H2 to setup a simple in-memory database to unit test stuff that reads from a database, but I don't know how I would test something that calls an Oracle DB stored procedure.

My best guess is that this would be the domain of integration testing and that you'd setup a temporary database and run some higher level (than unit) tests. Again, we're not terribly sophisticated in this sort of thing, so I don't even know how that would be done or what sort of tools/libraries/frameworks would be involved.

TLDR: How do you appropriately test whatever bit of Java code that interacts with your database, in particular calling Oracle stored procedures?

Zaphod42
Sep 13, 2012

If there's anything more important than my ego around, I want it caught and shot now.

FateFree posted:

It sounds like you don't care about code readability, or you wouldn't have said this was a waste of time when the entire purpose of it was to improve code readability! I just can't give someone credit about code readability when they openly dismiss something that improves code readability. I literally see no advantage to just 'leaving it because who cares' other than laziness.

My point in saying that line was to say there's no functional performance increase, so readability is the only concern. So in my opinion it wasn't a readability issue. I was just crossing off that potential reason since we hadn't yet established that it was for code readability. That doesn't mean I don't care about readability.

venutolo posted:

The developer never put it in for code review and I have no idea how QA didn't catch that the wrong end values were being written to the database. For the purposes of my question, let's assume that the code was reviewed but this small defect was missed. And let's assume that I want to catch this before it even goes to QA. So what sort of (automated) process might catch this thing?

We are not terribly sophisticated when it comes to automated testing. I write unit tests that provide good coverage for my code, but I'm kind of in the middle of the totem pole and don't set the culture/standards/expectations. So as a whole we really, really lack in unit testing and way too much of our code is not covered by any automated tests. That being said, I'm not sure how you would unit test this, or even if that is appropriate. Previously, I've used H2 to setup a simple in-memory database to unit test stuff that reads from a database, but I don't know how I would test something that calls an Oracle DB stored procedure.

My best guess is that this would be the domain of integration testing and that you'd setup a temporary database and run some higher level (than unit) tests. Again, we're not terribly sophisticated in this sort of thing, so I don't even know how that would be done or what sort of tools/libraries/frameworks would be involved.

TLDR: How do you appropriately test whatever bit of Java code that interacts with your database, in particular calling Oracle stored procedures?

You need to write a regressions test suite, with lots of sanity checking on each individual component as well as the overall operation. This can be a ton of test cases, but once you get the regressions suite going you can just add tests to it as you go.

Although this in particular is tough. All I can think of is adding a bunch of regressions tests that do sanity checking on the database. Yeah you'd definitely want to set up an example database, you should have a testing image with data, and you can have test cases that insert data, run tests, then clean up the data afterwards. So query for all kinds of data and see if anything is in any incorrect states after running each process that you're testing, like I guess you could query for start = end and throw flags if any data has the same values, and then also query for the expected results in the database and make sure they actually ended up there and nothing's missing. Its gonna be hard to think of everything though. For stored procedures all I can think of is generating new data, running the stored procedure, and then doing sanity testing on the database afterwards to make sure its all in the proper state. And just doing code review on the procedure itself to double check everything.

Zaphod42 fucked around with this message at 00:49 on Nov 17, 2016

Volguus
Mar 3, 2009

venutolo posted:

TLDR: How do you appropriately test whatever bit of Java code that interacts with your database, in particular calling Oracle stored procedures?

You don't. I mean, you don't need to. All you should do here is to mock JDBCTemplate and verify that the update method gets called with the parameters you expect (in this case, the appropriate query string, and appropriate parameters). A relatively decent mocking library is jMock. However, be careful with mocking things. You mock things because method X has a hard dependency on some service that you don't want to test at that time. Question is: can you do the test without that dependency? Can you refactor the code so that the test is testing what you need without mocking things?
In this particular case the answer is no, you really need to check what parameters are sent to the jdbcTemplate. But when you find yourself mocking a bazillion services to test one method, you should really consider refactoring the method. Don't ask how I know this :).

edit: Mocking things is not bad in and of itself. Abusing it, is. Show restraint when exercising your mocking powers.

Volguus fucked around with this message at 02:46 on Nov 17, 2016

Volguus
Mar 3, 2009

Ornithology posted:


Do I need to do something special in this case for Bootstrap styles to be applied?

No , you don't. If the CSS-es are downloaded they will be applied, no questions asked. You should check if they are downloaded though and applied via the developer tools in the browser you're using.

denzelcurrypower
Jan 28, 2011

Volguus posted:

No , you don't. If the CSS-es are downloaded they will be applied, no questions asked. You should check if they are downloaded though and applied via the developer tools in the browser you're using.

Sorry guys, I guess I was just being dumb or something but after messing around with different browsers and a bunch of other crap it ended up working in the end. It always seems I'm posting here with questions that aren't even legitimate issues.. god help me when I get to a real problem or two.

baka kaba
Jul 19, 2003

PLEASE ASK ME, THE SELF-PROFESSED NO #1 PAUL CATTERMOLE FAN IN THE SOMETHING AWFUL S-CLUB 7 MEGATHREAD, TO NAME A SINGLE SONG BY HIS EXCELLENT NU-METAL SIDE PROJECT, SKUA, AND IF I CAN'T PLEASE TELL ME TO
EAT SHIT

Ornithology posted:

Sorry guys, I guess I was just being dumb or something but after messing around with different browsers and a bunch of other crap it ended up working in the end. It always seems I'm posting here with questions that aren't even legitimate issues.. god help me when I get to a real problem or two.

Nah, the 'what... why???' stuff is real programming. Learning to track down the source of a problem and then work out what the hell is going on is fundamental, because there's always something. It'll help when you run into bigger problems

denzelcurrypower
Jan 28, 2011
Does anyone know of a good resource for learning how to create a Spring Web MVC project using Maven? The documentation for this seems to be all over the place and either doesn't correspond to the newest versions or is vague and has unexplained differences in file structure.

I even downloaded the Spring Tool Suite IDE to see if it would help, but it looks like it doesn't even have a way to create an empty Web MVC project.
Instead, I tried using this project provided in the spring.io documentation files as a starting point (https://github.com/spring-guides/gs-serving-web-content/tree/master/complete). However, for some reason it is missing important files like web.xml. I can't find any declaration of a view resolver anywhere and if I try to return jsp pages instead of html then I end up with 404 or 500 errors. I then found this sample project (https://github.com/spring-projects/spring-mvc-showcase) which looked more promising as it includes many more basic features and actually has important files/folders like web.xml and WEB-INF. However, when I try to run the project there's like 50 errors about missing files or incorrect references.... fun.

Anyway, if someone can suggest a guide or point me to a basic project structure diagram or something, I'd really appreciate the help. Bonus points for the same, but for Hibernate.

John F Bennett
Jan 30, 2013

I always wear my wedding ring. It's my trademark.

About functional programming in Java 8. I was doing a very simple loop:

code:
for (Item item : inventory) {
     output += item.getShortDescription();
}
My IDE suggested replacing it by this thing:

code:
output = inventory.stream().map((item) -> item.getShortDescription()).reduce(output, String::concat);
I have no idea how to read this and cannot imagine using something like this at this time. I know I have some studying to do regarding streams and such, but still.

Is this maybe a bad example for functional stuff and what are the actual advantages of doing things in this way?

pigdog
Apr 23, 2004

by Smythe

John F Bennett posted:

About functional programming in Java 8. I was doing a very simple loop:

code:
for (Item item : inventory) {
     output += item.getShortDescription();
}
My IDE suggested replacing it by this thing:

code:
output = inventory.stream().map((item) -> item.getShortDescription()).reduce(output, String::concat);
I have no idea how to read this and cannot imagine using something like this at this time. I know I have some studying to do regarding streams and such, but still.

Is this maybe a bad example for functional stuff and what are the actual advantages of doing things in this way?

That's not functional programming, it's just a bad example of lambdas. Which are actually really cool.

However a bigger problem in your code is that you are concatenating strings in a loop. In Java that means copying the whole string, every time, so that's O(n^2) complexity: very slow if your inventory has many items. Use a StringBuilder or StringBuffer that are designed for that very purpose.

A better example might be

code:
StringBuilder sb = new StringBuilder();
inventory.forEach(i -> sb.append(i.getShortDescription()));
output = sb.toString();
or an even better way, with streams:

code:
output = inventory.stream()
.map(Inventory::getShortDescription)
.collect(Collectors.joining())

pigdog fucked around with this message at 17:40 on Nov 23, 2016

John F Bennett
Jan 30, 2013

I always wear my wedding ring. It's my trademark.

Thanks for the tip! I will play around with this tonight.

I know about StringBuilder, but as the inventory will never contain more than 10 items, I decided to use the short version. This code will also only be run once, at the beginning of the program. But I will do it anyway, just for doing it the right way.

baka kaba
Jul 19, 2003

PLEASE ASK ME, THE SELF-PROFESSED NO #1 PAUL CATTERMOLE FAN IN THE SOMETHING AWFUL S-CLUB 7 MEGATHREAD, TO NAME A SINGLE SONG BY HIS EXCELLENT NU-METAL SIDE PROJECT, SKUA, AND IF I CAN'T PLEASE TELL ME TO
EAT SHIT

pigdog posted:

That's not functional programming, it's just a bad example of lambdas. Which are actually really cool.

Map/reduce is pretty functional!
e- oh you're saying it can be written better. Yeah IDEs have some weird suggestions sometimes

John F Bennett posted:

My IDE suggested replacing it by this thing:

code:
output = inventory.stream().map((item) -> item.getShortDescription()).reduce(output, String::concat);
I have no idea how to read this and cannot imagine using something like this at this time. I know I have some studying to do regarding streams and such, but still.

It's not really the best example considering how simple your loop is, but it basically says
  • turn the collection into a data stream
  • for each element, output the result of getShortDescription
  • reduce all those to a single result using String.concat

The idea is that you're describing what you want to do, instead of how to do it. You manipulate a stream of data with a kind of pipeline of functions that shape the end result. For more complicated processes, your intent is clearer (because you can just read the steps instead of working out what the code is doing), there's less chance of making a mistake (because you're using a set of basic functions that have been implemented for you, and you're not managing state), and you can get other benefits like parallelism and lazy evaluation for free

If you want a sort of bad analogy, it's like how a basic for loop gives you advantages over a while loop where you're managing a counter and checking an exit condition yourself. And how a for each gives you advantages over that, just handing you elements from an iterable so you don't have to pull them out with an index yourself. There's definitely a learning curve to functional stuff, and it's not always the best tool for the job, but it's definitely worth learning - especially since you seem to see it more and more, so at least being able to read it is important

It gives you a new perspective too, it's neat

baka kaba fucked around with this message at 11:44 on Nov 23, 2016

smackfu
Jun 7, 2004

If I want to do an action 5 times, is there a fancier way in modern Java than an old school for loop?

The Laplace Demon
Jul 23, 2009

"Oh dear! Oh dear! Heisenberg is a douche!"

smackfu posted:

If I want to do an action 5 times, is there a fancier way in modern Java than an old school for loop?

Not that I'm aware of in Java 8. There are sillier ways that may look fancier at first glance:

Java code:

IntStream.range(0, 5).forEach(ignored -> action());

I'd write the loop once in some static utility if you really want this:

Java code:

static void doTimes(final int times, final Runnable body) {
    for (int i = 0; i < times; i++) {
        body.run();
    }
}
// ...
doTimes(5, this::action);

baka kaba
Jul 19, 2003

PLEASE ASK ME, THE SELF-PROFESSED NO #1 PAUL CATTERMOLE FAN IN THE SOMETHING AWFUL S-CLUB 7 MEGATHREAD, TO NAME A SINGLE SONG BY HIS EXCELLENT NU-METAL SIDE PROJECT, SKUA, AND IF I CAN'T PLEASE TELL ME TO
EAT SHIT

The Laplace Demon posted:

I'd write the loop once in some static utility if you really want this:

Java code:
static void doTimes(final int times, final Runnable body) {
    for (int i = 0; i < times; i++) {
        body.run();
    }
}
// ...
doTimes(5, this::action);

Isn't that just a longer, janitored version of IntStream.range(0,5).forEach(this::action)?

CPColin
Sep 9, 2003

Big ol' smile.
IntStream.forEach() takes an IntConsumer, though, so you can't just pass this::action if it doesn't accept an integer parameter. Now you're jumping through hoops to get the signatures to fall in line and you'd be better off just using a normal loop.

baka kaba
Jul 19, 2003

PLEASE ASK ME, THE SELF-PROFESSED NO #1 PAUL CATTERMOLE FAN IN THE SOMETHING AWFUL S-CLUB 7 MEGATHREAD, TO NAME A SINGLE SONG BY HIS EXCELLENT NU-METAL SIDE PROJECT, SKUA, AND IF I CAN'T PLEASE TELL ME TO
EAT SHIT

Oh yeah I'm not saying do it, but if you're going to create a method that takes a runnable to run it in a for loop so you can call it with a method reference, you may as well just do the range thing

CPColin
Sep 9, 2003

Big ol' smile.
But you only have to write that function once, compared to writing IntStream.range(0,5).forEach(ignored -> this.action()) every time. (You can't use the method reference in that line if it doesn't accept an integer parameter.)

baka kaba
Jul 19, 2003

PLEASE ASK ME, THE SELF-PROFESSED NO #1 PAUL CATTERMOLE FAN IN THE SOMETHING AWFUL S-CLUB 7 MEGATHREAD, TO NAME A SINGLE SONG BY HIS EXCELLENT NU-METAL SIDE PROJECT, SKUA, AND IF I CAN'T PLEASE TELL ME TO
EAT SHIT

Yeah I just twigged the Runnable = no-args functional interface thing, which is weird because I just learned that the other day :negative:

You could still use a lambda though. If you have use for a utility function then great, if it's an occasional thing then the range / forEach style isn't much longer than calling the custom function. I probably wouldn't do it, but it's not that bad

Paul MaudDib
May 3, 2006

TEAM NVIDIA:
FORUM POLICE

baka kaba posted:

You could still use a lambda though. If you have use for a utility function then great, if it's an occasional thing then the range / forEach style isn't much longer than calling the custom function. I probably wouldn't do it, but it's not that bad

Counterpoint: both are bad and if you want to do that you should use Python.

Honestly that goes for C#'s LINQ too, it's a nice idea in theory but in practice it's a great way to kill your performance.

Gravity Pike
Feb 8, 2009

I find this discussion incredibly bland and disinteresting.

smackfu posted:

If I want to do an action 5 times, is there a fancier way in modern Java than an old school for loop?

Use the for loop. If the JVM determines that this code is a performance "hotspot," it'll "unroll" the loop, optimizing the code for you on the fly. (The JIT doesn't understand streams well enough to optimize around them, which is a damned shame.)

Janitor Prime
Jan 22, 2004

PC LOAD LETTER

What da fuck does that mean

Fun Shoe

Ornithology posted:

Does anyone know of a good resource for learning how to create a Spring Web MVC project using Maven? The documentation for this seems to be all over the place and either doesn't correspond to the newest versions or is vague and has unexplained differences in file structure.

I even downloaded the Spring Tool Suite IDE to see if it would help, but it looks like it doesn't even have a way to create an empty Web MVC project.
Instead, I tried using this project provided in the spring.io documentation files as a starting point (https://github.com/spring-guides/gs-serving-web-content/tree/master/complete). However, for some reason it is missing important files like web.xml. I can't find any declaration of a view resolver anywhere and if I try to return jsp pages instead of html then I end up with 404 or 500 errors. I then found this sample project (https://github.com/spring-projects/spring-mvc-showcase) which looked more promising as it includes many more basic features and actually has important files/folders like web.xml and WEB-INF. However, when I try to run the project there's like 50 errors about missing files or incorrect references.... fun.

Anyway, if someone can suggest a guide or point me to a basic project structure diagram or something, I'd really appreciate the help. Bonus points for the same, but for Hibernate.

Look at Spring Boot guides should get you rolling

Wheany
Mar 17, 2006

Spinyahahahahahahahahahahahaha!

Doctor Rope

Paul MaudDib posted:

Honestly that goes for C#'s LINQ too, it's a nice idea in theory but in practice it's a great way to kill your performance.

If it does, you can optimize it away.

Using functional programming in Java has not been the cause of performance problems in our project so far.

denzelcurrypower
Jan 28, 2011
Can anyone recommend a good resource to set up a BASIC spring MVC database connection layer to connect to MySQL database? I've spent the last week attempting various hibernate tutorials and now just basic jdbc access and nothing seems to work. All the guides inevitably list code without saying what file it belongs in or where, and it's getting extremely frustrating.

Volguus
Mar 3, 2009

Ornithology posted:

Can anyone recommend a good resource to set up a BASIC spring MVC database connection layer to connect to MySQL database? I've spent the last week attempting various hibernate tutorials and now just basic jdbc access and nothing seems to work. All the guides inevitably list code without saying what file it belongs in or where, and it's getting extremely frustrating.

A quick google gave me this: https://github.com/shagstrom/spring-mvc-hibernate-skeleton
I didn't look at it in great detail but it seems to do the job.
For a more detailed example checkout https://github.com/spring-projects/spring-mvc-showcase (and other repositories of spring-projects, they have examples for everything)

Boz0r
Sep 7, 2006
The Rocketship in action.
I'm trying to implement some concurrency locking functionality. I need to lock on objects, but I want the locks in a map, and remove them from the map when they're unused, but I can't figure out how to do it without errors or deadlocks. Here's what I have right now:

code:
public class Locker {

    private static final HashMap<Long, Semaphore> semaphores = new HashMap<Long, Semaphore>();

    public synchronized static Semaphore getMutex(Long ydId) {
        System.out.println("Trying to lock " + ydId);
        if (!semaphores.containsKey(ydId)) semaphores.put(ydId, new Semaphore(ydId));
        return  semaphores.get(ydId);
    }

    public synchronized static void removeMutex(Long ydId) {
        System.out.println("Removing lock " + ydId);
        Semaphore semaphore = semaphores.get(ydId);
        if (semaphore != null) {
            semaphore.decrement();
            if (semaphore.getCount() <= 0) {
                //System.out.println("Unused lock removed " + ydId);
                semaphores.remove(ydId);
            }
        }
    }
}
code:
public class MutexTestThread implements Runnable {

    private int id;
    Long ydId = 1L;

    public MutexTestThread(int id) {
        this.id = id;
    }

    @Override
    public void run() {
        synchronized (Locker.getMutex(ydId)) {
            Locker.getMutex(ydId).increment();
            TestFunction();
            Locker.removeMutex(ydId);
        }
    }

    public void TestFunction() {
        Main.errorCounter = Main.errorCounter + 1;
        try {
            Thread.sleep(Math.max(0, 100 - (id * 20)));
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            Main.errorCounter = Main.errorCounter - 1;
            if (Main.errorCounter != 0) System.out.println("Main.errorCounter: " + Main.errorCounter);
        }
    }
}
In this solution, sometimes errorCounter is different from 0. I tried switch the HashMap with a ConcurrentHashMap, but then I got a deadlock. Where did I gently caress up?

EDIT: If I use a ConcurrentHashMap and remove synchronized from the get and remove mutex functions, it doesn't deadlock, and doesn't seem to have errors. Is that a good idea?

EDIT: I just learned what WeakHashMap is. Could I use that instead? That would simplify the code a great deal.

Boz0r fucked around with this message at 10:32 on Dec 2, 2016

baka kaba
Jul 19, 2003

PLEASE ASK ME, THE SELF-PROFESSED NO #1 PAUL CATTERMOLE FAN IN THE SOMETHING AWFUL S-CLUB 7 MEGATHREAD, TO NAME A SINGLE SONG BY HIS EXCELLENT NU-METAL SIDE PROJECT, SKUA, AND IF I CAN'T PLEASE TELL ME TO
EAT SHIT

Well, a couple of things

Java code:
Main.errorCounter = Main.errorCounter + 1;
Java code:
Main.errorCounter = Main.errorCounter - 1;
If you're running this on multiple threads, with different mutexes (so there are threads which can run that code concurrently) you have a potential race condition. Each thread goes read value -> add 1 to it -> write new value, and the same happens with the decrement line. If another thread reads the current value before the first has finished updating it, you get this kind of thing happening:

pre:
Thread 1    read (5)      add (5+1)      write(6)

Thread 2                   read (5)        add (5+1)    write (6)
With multiple threads doing that (and also subtracting too) your end value could be all over the place. You'll want to use something that can do thread-safe atomic operations, like AtomicInteger


I can't really see why a ConcurrentHashMap would deadlock there, unless you're doing something like putIfAbsent in a compute operation - you'd have to post the code. I could be missing something though!

I think a WeakHashMap is fine there, so long as you're ensuring all access to it is synchronised like you're doing there


Also you probably shouldn't have the mutex holders doing that increment call themselves. Stick it in the Locker's getMutex function, so it's all encapsulated and the Locker handles all the counts internally. (It's not actually doing anything at the moment, the increment only happens once a thread enters the synchronised block, and it decrements it with the remove call before it leaves the block, so each mutex only ever has a count of 1 or 0)

baka kaba fucked around with this message at 13:02 on Dec 2, 2016

Boz0r
Sep 7, 2006
The Rocketship in action.
The race condition is what I'm trying to provoke in TestFunction(). I need to be sure that it locks the element. I've changed the code a bit, and it seems to be working now:

code:
public class Main {

    static int numYdelser = 3;
    static int numThreads = 8;

    static ConcurrentHashMap<Integer, Integer> errorCounters;

    public static void main(String[] args) throws InterruptedException {

        errorCounters = new ConcurrentHashMap<Integer, Integer>();

        for (int i = 0; i < numThreads; i++) {
            (new Thread(new TestThread(i))).start();
            Thread.sleep(Math.max(0, 100 - (i * 20)));
        }

        Thread.sleep(5000);

        log("Locker size: " + Locker.getInstance().size() + "\n" + Main.errorCounters.values());
    }

    static void increment(int i) {
        synchronized (errorCounters) {
            errorCounters.putIfAbsent(i, 0);
            errorCounters.put(i, errorCounters.get(i) + 1);
        }
    }

    static void decrement(int i) {
        synchronized (errorCounters) {
            errorCounters.putIfAbsent(i, 0);
            errorCounters.put(i, errorCounters.get(i) - 1);
        }
    }

    static int getCount(int i) {
        synchronized (errorCounters) {
            return errorCounters.get(i);
        }
    }

    public static void log(String s) {
        System.out.println(Thread.currentThread().getId() + "\t" + s);
    }
}
code:
public class Locker {

    private static Locker instance;

    private ConcurrentHashMap<Integer, Semaphore> semaphores;

    public static synchronized Locker getInstance() {
        if (instance == null) {
            synchronized (Locker.class) {
                if (instance == null) {
                    instance = new Locker();
                }
            }
        }
        return instance;
    }

    public Locker() {
        this.semaphores = new ConcurrentHashMap<Integer, Semaphore>();
    }

    public synchronized Semaphore get(int ydId) {
        semaphores.putIfAbsent(ydId, new Semaphore(ydId));
        semaphores.get(ydId).increment();
        return semaphores.get(ydId);
    }

    public synchronized void remove(int ydId) {
        Semaphore semaphore = semaphores.get(ydId);
        if (semaphore != null) {
            semaphore.decrement();
            if (semaphore.getCount() <= 0) {
                semaphores.remove(ydId);
            }
        }
    }

    private class Semaphore { 
        ...
    }
}
code:
public class TestThread implements Runnable {

    private int id;
    private int ydId;

    public TestThread(int id) {
        this.id = id;
        ydId = id % Main.numYdelser;
    }

    @Override
    public void run() {
        Main.log("Trying to lock " + ydId);
        synchronized (Locker.getInstance().get(ydId)) {
            Main.log(ydId + " LOCKED >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
            TestFunction();
            Locker.getInstance().remove(ydId);
            Main.log(ydId + " UNLOCKED <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");
        }
    }

    public void TestFunction() {
        int error = 0;
        Main.increment(ydId);
        try {
            Main.log(ydId + " Going to sleep");
            Thread.sleep(Math.max(0, 100 - (id * 20)));
            Main.log(ydId + " Waking up");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            Main.decrement(ydId);
            if (Main.getCount(ydId) != error) {
                Main.log("OH poo poo OH poo poo OH poo poo OH poo poo OH poo poo OH poo poo OH poo poo OH poo poo OH poo poo");
                Main.log("poo poo hosed UP!!!: " + Main.getCount(ydId) + " should be " + error);
                Main.log("OH poo poo OH poo poo OH poo poo OH poo poo OH poo poo OH poo poo OH poo poo OH poo poo OH poo poo");
            }
        }
    }
}

Boz0r fucked around with this message at 10:32 on Dec 5, 2016

Jabor
Jul 16, 2010

#1 Loser at SpaceChem
What are you actually trying to accomplish?

Boz0r
Sep 7, 2006
The Rocketship in action.
I have some data that needs to be processed. Because it depends on some other data, I need to be sure that multiple threads don't process the same data. The data is fetched from a database, so I don't think I can just lock on the object, as they may not be identical.

I'm trying to create a lock based on the ID, and save it in the map. If the next thread needs the same data, it can get the same lock, but if not, I want it removed from the map.

EDIT: I forgot to add the Main class to the post. The errorCounters map represents the data that needs to be processed.

Boz0r fucked around with this message at 10:33 on Dec 5, 2016

Jabor
Jul 16, 2010

#1 Loser at SpaceChem
You seem to be way overthinking this. Even with your description, it's entirely not clear why it needs to be so complex.

What do you mean by "don't process the same data"? Is this a problem about distributing work to individual threads, or does this processing involve mutating the data?
What aspect of the processing means that multiple threads might need to access the same data?
What lead you to thinking Semaphores would be the appropriate solution to your problem?

Boz0r
Sep 7, 2006
The Rocketship in action.

Jabor posted:

You seem to be way overthinking this. Even with your description, it's entirely not clear why it needs to be so complex.

What do you mean by "don't process the same data"? Is this a problem about distributing work to individual threads, or does this processing involve mutating the data?
What aspect of the processing means that multiple threads might need to access the same data?
What lead you to thinking Semaphores would be the appropriate solution to your problem?

The processing involves mutating the same data. The semaphore idea is from the lead dev, so I'm just falling in line :D. I'm very open to better solutions.

Boz0r fucked around with this message at 11:05 on Dec 5, 2016

Jabor
Jul 16, 2010

#1 Loser at SpaceChem
It sounds like if you distribute the work appropriately (so that two threads aren't going to process the same data), then everything just works?

So really it's just a work-distribution problem. The easiest way is to have a single thread determine which items need to be processed and use a thread pool to handle the actual execution:

code:
ExecutorService pool = Executors.newFixedThreadPool(threadsToUse);
for (WorkItem item : getItemsToProcess()) {
  pool.execute(() -> { processItem(item) });
}
pool.shutdown();

Volguus
Mar 3, 2009
From your example everything looks to be more complicated than it needs to be. If you would have ConcurrentHashMap<Integer, AtomicInteger> you can get rid off synchronized, Sempahore and ... pretty much everything else. Can simply put into the map and increment the key when needed without worries.
But, the first question is : do you have to mutate the same object from multiple threads? Can you do without?

PierreTheMime
Dec 9, 2004

Hero of hormagaunts everywhere!
Buglord
I have a process to pull data about an Object out of a database and then check a value of that data, only performing work on the Object if it a) exists and b) isn't in read-only mode due to editing. If the Object doesn't exist the pull request returns a null value, which in turn throws a NullPointerException if the second condition is checked. What is the best method for writing a condition check for these two? I could just write them separately, but I figure this is a good learning moment.

poemdexter
Feb 18, 2005

Hooray Indie Games!

College Slice

Janitor Prime posted:

Look at Spring Boot guides should get you rolling

Seconded. Spring Boot and latest Spring framework in general means no more web.xml and no more WEB-INF folders. gently caress XML configuration forever. Also Gradle is a great replacement for Maven.

Paul MaudDib
May 3, 2006

TEAM NVIDIA:
FORUM POLICE
The nice thing about Maven is it is declarative though - which makes it trivial to use as an IDE-agnostic project file. Literally any IDE can look at a POM file and spit out a working project, so you can just go ahead and git-ignore all IDE-specific project files from the repo forever and never worry about project files getting out of date or that one idiot who just can't help but check them in every single time clobbering your project config updates.

If you still want to have your "libs" dir that can build the whole app without any dependency downloads, you can still do that by installing everything into a local repository and naming it in your POM file. Ideally you will give the path relative to ${project.basedir} for portability. You pretty much need to do this for some stuff anyway, like the Oracle OJDBC drivers or some of the Java EE JARs that aren't in Maven-Central due to licensing concerns. This applies to Gradle too of course.

Also, as much as Maven has its bugs, at least it's not so slow that it needs to live as a resident daemon :lol:

Paul MaudDib fucked around with this message at 01:24 on Dec 6, 2016

Zaphod42
Sep 13, 2012

If there's anything more important than my ego around, I want it caught and shot now.

PierreTheMime posted:

I have a process to pull data about an Object out of a database and then check a value of that data, only performing work on the Object if it a) exists and b) isn't in read-only mode due to editing. If the Object doesn't exist the pull request returns a null value, which in turn throws a NullPointerException if the second condition is checked. What is the best method for writing a condition check for these two? I could just write them separately, but I figure this is a good learning moment.

Writing them separately is pretty much fine and you shouldn't try to overthink it.

That said, logical short-circuiting works pretty drat well here.

code:
If(obj != null && ! obj.getReadOnlyMode()){

//do stuff

}
else{
//handle null/read-only state
}
This works because in an if() clause, if you require logical AND the computer knows that as soon as it sees a 'false' the overall result will be False. False AND X where X is anything returns False. So the Java engine doesn't even bother calculating the rest of the clause, so it never calls obj.getReadOnlyMode();

The same thing works on OR, but in reverse. With OR as soon as it sees a true value it short-circuits since TRUE OR X always yields True.

But that's just fancy syntactic sugar really to make the code simple, you don't need it. There is *nothing* wrong with this:

code:
if(obj != null){
  if(obj.getReadOnlyMode()){
//handle read only
}
else{
//handle object
}
}
else{
// handle null
}
You just don't want the two of them on the same level. If you do if(obj != null) and if(obj.getReadOnlyMode()) then the second will NPE on the null condition. You either need to nest the second check inside the check for null, or you need to inline them as part of the same clause.

Adbot
ADBOT LOVES YOU

Zaphod42
Sep 13, 2012

If there's anything more important than my ego around, I want it caught and shot now.

Paul MaudDib posted:

The nice thing about Maven is it is declarative though - which makes it trivial to use as an IDE-agnostic project file. Literally any IDE can look at a POM file and spit out a working project, so you can just go ahead and git-ignore all IDE-specific project files from the repo forever and never worry about project files getting out of date or that one idiot who just can't help but check them in every single time clobbering your project config updates.

If you still want to have your "libs" dir that can build the whole app without any dependency downloads, you can still do that by installing everything into a local repository and naming it in your POM file. Ideally you will give the path relative to ${project.basedir} for portability. You pretty much need to do this for some stuff anyway, like the Oracle OJDBC drivers or some of the Java EE JARs that aren't in Maven-Central due to licensing concerns. This applies to Gradle too of course.

Also, as much as Maven has its bugs, at least it's not so slow that it needs to live as a resident daemon :lol:

I find doing that is a huge pain in the butt compared to just dropping libs in a "libs" dir though.

What I'd really prefer to Maven would be a system where you have a libs dir and then Maven just automatically downloads and places libs into the libs dir based on dependencies. Any files that were not part of the Maven POM file would be ignored in the libs dir, so you could have your own libraries that Maven doesn't know about, but Maven would also pull things for you automatically and replace the old versions, more like a package manager. Then you'd have a totally portable folder that can compile without Maven. Make it more of a setup tool. My problem is that Maven itself ends up becoming a dependency that anybody who wants to deal with your project has to deal with. I really love being able to just rip a lib from an FTP site and compile right away without having to edit POM files. That's great for the big heavyweight stuff with lots of dependencies and versions, but for some small lightweight libs its super overkill and takes too long to get going.

I don't know why they don't just build that as a feature into Maven, even. "Maven copy dependencies" would build a libs dir or something to that effect. But I guess its kinda anathema to Maven's mentality, so it'd have to be some other software to offer that kinda approach.

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply